全局组件和局部组件
组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。
注册一个全局组件语法格式如下:
Vue.component(tagName, options)
tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件:
<tagName></tagName>
所有实例都能用全局组件。当然我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
<div id="app">
<runoob></runoob>
<child></child>
</div>
<script>
// 注册全局组件
Vue.component('runoob', {
template: '<h1>自定义全局组件!</h1>'
})
var Child = {
template: '<h1>自定义局部组件!</h1>'
}
// 创建根实例
new Vue({
el: '#app',
components: {
// 局部组件,<child> 将只在父模板可用
'child': Child
}
})
</script>
Props
prop 是子组件用来接受父组件传递过来的数据的一个自定义属性。父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
<div id="app">
<input v-model="parentMsg">
<br>
<child v-bind:message="parentMsg"></child>
</div>
<script>
// 注册
Vue.component('child', {
// 声明 props
props: ['message'],
// 同样也可以在 vm 实例中像 “this.message” 这样使用
template: '<span>{{ message }}</span>'
})
// 创建根实例
new Vue({
el: '#app',
data: {
parentMsg: '父组件内容'
}
})
</script>
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件。注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
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
}
}
}
})
当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。
type 可以是原生构造器:String,Number,Boolean,Array,Object,Date,Function,Symbol。
type 也可以是一个自定义构造器,使用 instanceof 检测。
组件自定义事件
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
- 使用
$on(eventName)
监听事件 - 使用
$emit(eventName)
触发事件
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
<div id="app">
<div id="counter-event-example">
<p>{{ total }}</p>
<button-counter v-on:increment="incrementTotal"></button-counter>
<button-counter v-on:increment="incrementTotal"></button-counter>
</div>
</div>
<script>
Vue.component('button-counter', {
template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
// data 不是一个对象,而是一个函数
// 这样的好处是每个实例可以维护一份被返回对象的独立的拷贝,不会影响到其他实例
data: function () {
return {
counter: 0
}
},
methods: {
incrementHandler: function () {
this.counter += 1
this.$emit('increment')
}
},
})
new Vue({
el: '#counter-event-example',
data: {
total: 0
},
methods: {
incrementTotal: function () {
this.total += 1
}
}
})
</script>
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
<my-component v-on:click.native="doTheThing"></my-component>
自定义组件的 v-model
组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件。
<input v-model="parentData">
// 上面等价于下面
<input
:value="parentData"
@input="parentData = $event.target.value"
>
使用实例如下:
<div id="app">
<runoob-input v-model="num"></runoob-input>
<p>输入的数字为:{{num}}</p>
</div>
<script>
Vue.component('runoob-input', {
template: `
<!-- 包含了名为 input 的事件 -->
<input :value="value" @input="$emit('input', $event.target.value)">`,
props: ['value'], // 名为 value 的 prop
})
new Vue({
el: '#app',
data: {
num: 100,
}
})
</script>
由于 v-model 默认传的是 value,不是 checked,所以对于复选框或者单选框的组件时,我们需要使用 model 选项,model 选项可以指定当前的事件类型和传入的 props。
<div id="app">
<base-checkbox v-model="lovingVue"></base-checkbox>
<div v-show="lovingVue">如果选择框打勾我就会显示。</div>
</div>
<script>
// 注册
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change' // onchange 事件
},
props: {
checked: Boolean
},
template: `
<input type="checkbox" v-bind:checked="checked"
v-on:change="$emit('change', $event.target.checked)">`
})
// 创建根实例
new Vue({
el: '#app',
data: {
lovingVue: true
}
})