组件使用分为三个步骤:
1.创建组件构造器对象(调用Vue.extend()方法创建组件构造器)
2.注册组件(调用Vue.component()方法注册组件)
3.使用组件(在Vue实例的作用范围内使用组件)
使用实例:
1.创建
const myComponent = Vue.extend({
template:`
<div>
some contents
</div>
`
});
2.注册(全局组件)
Vue.component('my-cpn',myComponent );
3.使用
在vue实例管理的html代码中使用<my-cpn></my-cpn>即可。
cpn就是component的缩写
注意``是ES6中的语法,类似于引号’和双引号",但功能更强大,换行时可以不用使用+连接。
//注册局部组件
const app = new Vue({
el: "#app",
data: {},
components: {
'my-cpn': myComponent,
}
});
//注册父子组件
const childCpn= Vue.extend({
template:`
<div>
i am child.
</div>
`
});
const parentCpn = Vue.extend({
template:`
<div>
i am parent.
<child-cpn></child-cpn>
</div>
`,
components:{
'child-cpn':childCpn,
}
});
注册组件的语法糖:就是把Vue.extend()方法所需的对象参数直接替换到原来的组件构造器对象cpn处。就省略了Vue.extend()。但实际上源码中还是调用的Vue.extend()。
//提取template模板
//第一种方法
<script type="text/x-template" id="cpn">
some html contents.
</script>
<script>
Vue.component({
'my-cpn': '#cpn',
})
</script>
//第二种写法
<template id="cpn2">
some html contents.
</template>
<script>
Vue.component({
'my-cpn2': '#cpn2',
})
</script>
Vue实例可以看成是根组件,root组件。
注册组件写法的演变过程
1.最原始的3步注册组件。
2.省略Vue.extend()。
3.提取template模板。
组件的data必须是函数。
原因:因为函数每次返回的data数据是新对象,组件多次复用时,相互之间数据是没有影响的。
子组件不能直接访问父组件或者Vue实例中的数据。这就涉及到了数据的传递。
父子组件的通信方式:(注意驼峰命名)
1.通过props从父组件向子组件传递数据
①方式一:字符串数组,数组中的字符串就是传递时的名称。
②方式二:对象,对象可以设置传递时的类型,也可以设置默认值等。
注意:
props传递时的驼峰命名以前的版本不支持,要根据驼峰用-分割,比如myFirstChildMessage要写成my-first-child-message。据说是因为html对大小写不敏感。在高版本中,该问题可能已经解决。
<div id="app">
<cpn :my-first-child-message="message"></cpn>
</div>
问题报错:vue Expected Boolean, got String with value “false”
解决:这种情况是有一些属性的值应该填写Boolean类型,但是当前的值可能是“”字符串。这种情况只需要在属性前面加上:即可。
2.通过事件从子组件向父组件发送消息
在子组件中发射自定义事件‘item-click’
this.$emit('item-click',要传递的对象)
在父组件处接受自定义事件‘item-click‘,此处的cpnClick不加()默认会传递子组件传递过来的对象。因为是自定义事件,不会像click事件那样有浏览器的$event对象。
<div id="app">
<cpn @item-click="cpnClick"></cpn>
</div>
3.兄弟组件间通信
兄弟组件之间的通讯是通过父组件作为中间媒介来进行通讯的。
组件的template模板下有很多标签时,要用
<div></div>
标签包起来。
watch()
this.$children //获取的为全部的子组件,数组类型
this.$refs //获取的为所有包含ref属性的子组件,对象类型
this.$parent //上一级组件,对象类型
this.$root //根组件,对象类型
slot插槽:组件的插槽是为了让封装的组件功能更强大,更加具有扩展性。可以分为匿名插槽,具名插槽,作用域插槽。
<slot></slot>可以有默认值
<slot name=""></slot>具名插槽,可以替换指定插槽
作用域插槽(编译作用域的问题,在#app的div的Vue实例中无法直接使用子组件中的数据xxx)
<div id="app">
<cpn>
<!-- 目的是获取子组件中的数据属性,此处不要求必须是template标签,也可以是其他包裹标签。 -->
<template slot-scope="slot">
<span>{{slot.xxx.join("-")}}</span>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<!-- xxx名字可以随意起 -->
<slot :xxx="pLanguage">
<ul>
<li v-for="item in pLanguage">{{item}}</li>
</ul>
</slot>
</div>
</template>
v-slot的出现是为了代替原有的slot和slot-scope,简化了一些复杂的语法,可以缩写为#
一句话概括就是v-slot :后边是插槽名称,=后边是组件内部绑定作用域值的映射。
<meta name="viewport" content="width=device-width, initial-scale=1.0">