[TOC]
组件定义
首先规定我们组件名称为my-com
,我们可以以如下形式在html中使用它 , 之后我们将介绍组件定义的三种方式, 每种定义所用组件名均为my-com
1 2 3
| <div id="app"> <my-com></my-com> </div>
|
- 在Vue.component中编写模板
1 2 3
| Vue.component('my-com',{ template: '<h3> this is my component </h3>' })
|
- 在Vue实例中定义私有组件
1 2 3 4 5 6 7 8 9 10 11
| <script> let mc = { template: '<h3> this is my component - </h3>' } new Vue({ el: '#app', components: { 'my-com': mc } }) </script>
|
- Vue.extend定义组件,Vue.component注册组件,也可以用在Vue实例中
1 2 3 4 5 6
| var mc = Vue.extend({ template: '<h3> this is my component </h3>' });
Vue.component('my-com',mc);
|
- render渲染组件,一般在webpack中这样写,另外,使用render渲染的组件会覆盖挂载实例
1 2 3 4 5 6 7 8
| var login = { template: '' }
let app = new Vue({ el: '#app', render: mountComponent => mountComponent(login) })
|
组件模板也可以这样写:在Vue.component中定义组件,在html中编写模板,这样有语法高亮和自动补全
1 2 3 4 5 6 7 8 9
| <template id="mc"> <h3> this is my component ! </h3> </template>
<script> Vue.component('my-com', { template: '#mc' }) </script>
|
插槽
这里将会讲些插槽的基本使用、插槽默认之、具名化插槽一些知识
如果组件不加插槽slot
,那么在html代码中,所有组件内部的代码都会被覆盖,比如下面这段代码,my-com
组件下的h1
标签和内容都不会被展示,只会被组件本身覆盖:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <div id="app"> <my-com c='a'> <h1> xx </h1> </my-com> </div>
--- template: ` <div> <p> 1 </p> </div> `
|
$ show 1
有了slot,我们就可以在html组件代码内部插入其他html代码(如果不插入,则使用插槽的默认值,这里是hhh):
1 2 3 4 5 6
| template: ` <div> <p> 1 </p> <slot> hhh </slot> </div> `
|
$ show 1
xx
每一个插槽都有一个名字,可以使用name
指定,如果没有指定,那么隐含名为default
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| Vue.component('my-component', { template: ` <button> button <slot name="header">slot header</slot> <slot name="body">slot body</slot> <slot name="footer">slot footer</slot> </button> ` });
--------- <div id="app" style="font-size:20px"> <my-component> <template v-slot:header> <p> 用户指定插槽的header </p> </template> <template v-slot:footer> <p> 用户指定插槽的footer </p> </template> </my-component> </div>
|
动态绑定
有些组件只能存在于特定的位置,比如<table>
只能存在<tr>
, 对于这样的情况,我们可以用is
指定组件:
1 2 3 4 5
| <table> <tr is="my-row"></tr> </table>
Vue.component('my-row',{...})
|
这样还可以做成动态组件,比如:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <keep-alive> <!-- 修改comoose的值,就可以动态改变页面上这个位置的组件 --> <component v-bind:is="comoose"> </component> </keep-alive>
new Vue({ el: '', data: { comoose: 'com1' } })
|
一个动态组件标签切换的小demo:

组件中的Options
一个组件的基本结构大致如下:
1 2 3 4 5 6 7 8 9
| { inheritAttrs: false, // 禁止继承根元素的属性,inheritAttrs不会影响style和class的绑定 props: [] | {}, // 接受html代码中传过来的属性值 model:{}, // 覆盖默认绑定的值和方法,(checkbox默认绑定value值和click方法) data: {}, // 组件私有数据 methods: {}, // 组件私有方法 computed: {}, // 组件的计算属性 template: `` // 组件模板 }
|
概述
一个示例代码(从<body>
到 </body>
):
- 实现了一个计数器,并且鼠标悬停会有’this is a title in vue instance’的提示语
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <div id="app"> <my-com v-bind:title='tl'></my-com> </div>
<script> Vue.component('my-com', { props: ['title'], data: function () { return { count: 1 } }, methods: { increase: function () { this.count += 1 } }, template: '<button @click="increase" :title="title"> click me {{ count }} </button>' })
new Vue({ el: '#app', data: { tl: 'this is a title in vue instance' } }) </script>
|
props
props可以用数组接受参数,但是这样接受的参数不能进行类型校验,想要进行类型校验,我们可以用对象来接受参数
props类型检查:https://cn.vuejs.org/v2/guide/components-props.html#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| 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 } } } })
|
1 2 3 4 5 6 7 8 9
| props: { title: String, likes: Number, // 如果不是Number,则会转为Number isPublished: Boolean, commentIds: Array, author: Object, callback: Function, contactsPromise: Promise // or any other constructor }
|
例子:
如果传递的值不是Number,则显示原值,控制台输出error:Invalid prop: type check failed for prop "v". Expected Number with value NaN, got String with value "12px"
这里依旧展示为:12px
1 2 3
| <div id="app"> <my-com :v="msg"></my-com> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Vue.component('my-com', { props: { v: Number, require: true }, template: '<p> {{ v }} </p>' })
new Vue({ el: '#app', data: { msg: '12px' } })
|
组件间通信
组件间通信可以通过props
实现,也可以通过子组件触发父组件函数的方式来实现,下面介绍一下函数的实现方式:
- 首先在子组件和Vue实例中分别定义一个函数
- 在html代码和html模板中分别调用这个函数
- 在模板方法中使用
this.$emit(funcName)
触发父组件的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <div id="app"> <my-com @func='showmsg'></my-com> </div>
<script> Vue.component('my-com', { methods: { show: function(){ this.$emit("func"); } }, template: '<button @click="show"> click me </button>' })
new Vue({ el: '#app', methods: { showmsg: function(){ alert("i'm in the vue instance"); } } }) </script>
|

this.$emit(funcName , args ); 这个方法接受的第一个参数为函数名, 之后可以传任意参数, 均作为数据部分传递给funcName, funcName可以这样定义:
1 2 3 4 5
| funcName: function(data){ console.log(data) } ,,,, this.$emit(funcName,'hello');
|
组件中的this
下面介绍this
中的常用方法和属性
1 2 3 4 5 6 7 8 9 10 11 12 13
| $attrs: (...) // 从父组件那接收到的所有属性,对象类型,结构为: { key: value} $children: [] $el: div // 当前挂载的DOM元素,就是template的根元素 $listeners: (...) // 监听器,可以重写监听器实现多元素事件绑定 $options: // 记录了Vue的父节点等信息 $parent: // 同$parent = $options.parent $refs: {} // 用户获取声明的DOM元素 $root: Vue // 当前组件的根节点,是html代码中组件位置所属的根节点 $slots: {} // 插槽 $vnode: VNode $data: (...) // 组件私有变量 $props: (...) // 接受的属性参数
|
$attrs
的用法:

$listeners
的用法(多元素下的单独事件绑定):

$model
的用法(重写默认事件和属性)
实现点击checkbox
,选中为true
,取消为false
的效果:

- checkbox 和 radio 使用 checked property 和 change 事件;
- 点击勾选框,触发click事件
- click函数中$emit-switch事件
- 向switch函数中传入$event.target.checked,改变checkVal的值
- 原来的change方法被重写为switch
- 原来的value属性被重写为checkVal
click –> switch($event.target.checked) –> checkVal
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| <!DOCTYPE html> <html lang="en">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>10-20 Vue</title> <script src="../lib/vue.js"></script> </head>
<body> <div id="app"> <my-com v-model="checkVal"></my-com> </div>
<template id="mytmp"> <div> <input type="checkbox" v-bind:checked='checkVal' v-on:click="$emit('switch',$event.target.checked)"> {{ checkVal }} </div> </template>
<script> Vue.component('my-com', { model: { prop: 'checkVal', event: 'switch' }, props: ['checkVal'], template: '#mytmp' }); new Vue({ el: '#app', data: { checkVal: false } }) </script> </body>
</html>
|