1、在Vue中全局注册
//my-component就是注册的组件自定义标签名,推荐使用小写加减号分割的形式命名
//template的DOM结构必须被一个元素包含(这里是div),否则无法渲染
Vue.component('my-component', {template: '我是组件'});
var app = new Vue({
//选择元素
el: "#app"
});
在html中使用组件:
使用全局注册的时候,组件必须先注册,然后再实例化Vue;全局注册的组件,任何Vue实例都可以使用。
2、在Vue实例中,注册局部组件
注册的局部组件只有在该实例作用域下有效。组件也可以使用components选项来注册组件,使组件可以嵌套。
var child = {
template: '局部注册组件的内容'
}
var app = new Vue({
el: '#app',
components: {
'my-component': child
}
});
3、组件中的data
组件中的配置选项与Vue实例很类似,在组件中使用data时,data必须是函数,然后将数据return出去,例如:
Vue.component('my-component', {
template: '{{ name }}',
/* 子组件的data必须是一个函数 */
data: function() {
return {
name: '子组件的数据'
}
},
methods: {
handleClick($event){
$event.target.style.color = 'red';
alert('子组件的click事件');
}
}
});
var app = new Vue({
el: "#app"
});
组件不仅仅是要把模板的内容进行复用,更重要的是组件间要进行通信。通常父组件的模板中包含子组件,父组件要正向地向子组件传递数据或参数,子组件接收到后根据参数的不同来渲染不同的内容或执行操作。props的值可以是两种,一种是字符串数组,一种是对象。
1、父组件向子组件传递数据,使用props来实现
在组件中,使用选项props来声明需要从父级接收的数据。我们来看一个最简单的例子,直接给子组件传递一个字符串:
Vue.component('my-component', {
props: ['message'],
template: '{{ message }}'
});
var app = new Vue({
el: "#app"
});
上面代码中,我们给子组件设置了一个自定义的属性message,它的值是父组件想要传递给子组件my-component的值,这里是固定的一个字符串。运行结果如下:
说明:由于html特性不区分大小写,当使用DOM模板时,驼峰命名的props名称要转为短横分隔命名,比如props:['warningText'],在组件定义这个属性时候应该这样写:warning-text="来自父组件的信息" (如果使用的是字符串模板(单个vue文件),可忽略这些限制)
props中声明的数据与组件data函数return的数据主要区别就是props的来自父级,而data中的是组件自己的数据,作用域是组件本身,这两种数据都可以在模板template及计算属性computed和方法methods中使用。
有时候,传递的数据并不是直接写死的,而是来自父级的动态数据,这时可以使用指令v-bind来动态绑定props的值,当父组件的数据变化时,也会传递给子组件。
Vue.component('my-component', {
props: ['message'],
template: `
子组件自身的数据:{{ name }},
来自父组件的数据:{{ message }}
`,
data: function() {
return {
name: '我是子组件自带的数据'
}
}
});
var app = new Vue({
el: "#app",
data: {
parentMessage: '我是父组件的message',
}
});
可以看到,这个例子与上一个例子有个很明显的区别,这里使用v-bind绑定了自定义的属性message的值,message保存了父组件parentMessage的值;子组件通过props接收message保存的值,同时template可以像访问data一样,访问props里面的message;输出效果如下:
注意、如果直接传递数字,布尔值、数组、对象,而且不使用v-bind,传递的仅仅是字符串;例如:
Vue2.X通过props传递数据是单向的,也就是父组件数据变化时会传递给子组件,但是反过来不行。通常在业务中经常会遇到两种需要改变prop的情况,代码如下:
一般当你的组件需要提供给别人使用时,推荐都进行数据验证;如果传入的值类型不对,就会在控制台弹出警告。例如:
Vue.component('my-component', {
template: 'props的值为数组时,接收父组件数据:{{ propA }},接收数值类型:{{ propD }}',
props: {
// 必须是数字类型
propA: Number,
// 必须是字符串或数字类型
propB: [String, Number],
// 布尔值,如果没有定义,默认值就是true
propC: {
type: Boolean,
default: true
},
//数字,而且是必传
propD: {
type: Number,
required: true
},
//如果是数组或对象,默认值必须是一个函数来返回
propE: {
type: Array,
default: function () {
return [];
}
},
//自定义一个验证函数
propF: {
validator: function (value) {
return value > 10;
}
}
}
});
var app = new Vue({
el: '#app',
data: {
parentData: 123,
count: 456
}
});
以上代码如果我们在子组件里不传入prop-d,就会在控制台报错,因为propD是必传项;验证的type类型可以是:String,Number,Boolean,Object,Array,Function;type也可以是一个自定义构造器,使用instanceof检测。
2、子组件向父组件传递数据,使用自定义事件
子组件需要向父组件传递数据时,就要用到自定义事件;v-on除了监听DOM事件外, 还可以用于组件之间的自定义事件。
子组件用$emit来触发事件,父组件用$on()来监听子组件的事件。 父组件可以直接在子组件的自定义标签上使用v-on(语法糖@)来监听子组件触发的自定义事件
总数:{{ total }}
以上代码使用@(v-on)监听子组件的increase和reduce自定义事件,一旦子组件触发了这两个事件,父组件就会立即执行handleGetTotal方法,同时接收子组件传递过来的参数(数据);
Vue.component('my-component', {
template: `
`,
data: function () {
return {
counter: 0
};
},
methods: {
handleIncrease: function () {
this.counter++;
// 触发自定义的increase事件,同时将自身的counter数据传递过去
this.$emit('increase', this.counter);
},
handleReduce: function () {
this.counter--;
// 触发自定义的reduce事件
this.$emit('reduce', this.counter);
}
}
});
var app = new Vue({
el: '#app',
data: {
total: 0
},
methods: {
handleGetTotal: function (total) {
this.total = total;
}
}
});
子组件在按钮上绑定click事件,当点击按钮时,执行自身methods里的方法,这两个方法使用vue实例的$emit来触发自定义事件increase或reduce;
除了用v-on在组件上监听自定义事件外,也可以监听DOM事件,这时可以用.native修饰符表示监听的是一个原生事件,监听的是该组件的根元素。例如:
var app = new Vue({
el: '#app',
data: {
total: 0
},
methods: {
handleGetTotal: function (total) {
this.total = total;
},
handleClick: function () {
alert('监听子组件的原生click事件的处理函数要写在父组件上');
}
}
});
Vue 2.X可以在自定义组件上使用v-model指令,示例如下:
总数:{{ total }}
使用v-model指令创建自定义的表单输入组件:
总数:{{ total }}
Vue.component('my-component', {
props: ['value'],
template: '',
methods: {
updateValue: function (event) {
this.$emit('input', event.target.value);
}
}
});
var app = new Vue({
el: "#app",
data: {
total: 0
},
methods: {
handleReduce: function () {
this.total--;
}
}
});
以上代码执行过程个人理解:
通过v-model和props将父组件的total值传递给了input;
input使用v-bind绑定了父组件传递过来的值;同时绑定了input事件,当输入新的input值时,通过updateValue处理函数执行$emit('input', event.target.value)将输入的新值传回给父组件的total;(这里面发生了父组件向子组件传值以及子组件给父组件传值的过程,都得益于v-model)
显示效果如下: