Vue学习2:组件化开发(基本知识、父子间通信、slot、模块化开发)
组件化:
组件化是Vue.js中的重要思想,它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用。任何的应用都会被抽象成一颗组件树。
1.创建组件构造器:Vue.extend()
//1.创建组件构造器对象
const cpnC = Vue.extend({
template: `
标题
内容
`
});
2.注册组件:Vue.component('my-cpn', cpnC);
创建构造器+注册语法糖(更常用):就是把template的内容直接写到cpnC中,省去extend这一步
全局组件:
Vue.component('myCpn', {
template: `
标题
内容
`
})
局部组件:
const app = new Vue({
el: '#app',
data: {
},
components: {
myCpn: {
template: `
标题
内容
`
}
}
})
3.使用组件:在Vue实例的作用范围内(id="app"内)使用
全局组件:可以在多个Vue实例下使用
在Vue外部注册的:Vue.component('myCpn', cpnC);
局部组件:只能在特定的Vue实例下使用(用得更多)
在Vue中写在components中:components: { myCpn: cpnC }
app是cpnC2的父级(可看作root),cpnC2是cpnC1的父级,只有注册了,才可以在其实例范围下使用
<script>
const cpnC1 = Vue.extend({
template: `
标题1
内容1
`
});
const cpnC2 = Vue.extend({
template: `
标题2
内容2
`,
components: {
cpn1: cpnC1
}
});
const app = new Vue({
el: '#app',
data: {
},
components: {
cpn2: cpnC2
}
})
</script>
组件中的html结构要使用数据,使用组件中的data来设置,data是一个函数,返回一个对象
为什么是一个函数?因为当多次使用组件时,data是函数的形式,则会重新调用函数,里面的数据对于每个组件来说是私有的,不是公用的
<body>
<div id="app">
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<!-- html结构分离 -->
<template id="cpn1">
<h2>{
{
title1}}</h2>
</template>
<template id="cpn2">
<h2>{
{
title2}}</h2>
</template>
<script src="../vue.js"></script>
<script>
//全局组件
Vue.component('cpn1', {
template: '#cpn1',
data() {
//注意data是一个函数 返回一个对象
return {
title1: '全局组件'
}
}
})
const app = new Vue({
el: '#app',
data: {
},
components: {
cpn2: {
template: '#cpn2',
data() {
//data是函数 返回一个对象
return {
title2: '局部组件'
}
}
}
}
})
</script>
</body>
在开发中,往往需要上层组件请求网络数据,再传递给下面的组件进行展示
父子组件间通信:
1.通过props向子组件传递数据
2.通过事件向父组件发送消息
props
:
<body>
<div id="app">
<!-- 要用v-bind语法绑定数据 -->
<cpn :cmovies="movies" :cmessage="message"></cpn>
</div>
<template id="cpn">
<div>
<p>{
{
cmessage}}</p>
<ul>
<li v-for="item in cmovies">{
{
item}}</li>
</ul>
</div>
</template>
<script src="../vue.js"></script>
<script>
const app = new Vue({
//相当于父组件
el: '#app',
data: {
message: 'vivian',
movies: ['海贼王', '柯南', '火隐忍者', '蜡笔小新']
},
components: {
cpn: {
//子组件
template: '#cpn',
// 属性,里面是属性名
// 写法一:数组形式
// props: ['cmovies', 'cmessage']
//写法二:类型限制
// props: {
// cmovies: Array,
// cmessage: String
// }
//写法三:有默认值
props: {
//类型是对象或者数组时,默认值必须是一个函数
cmovies: {
type: Array,
default() {
return []
}
},
cmessage: {
type: String,
default: 'aaa',
required: true
}
}
}
}
})
</script>
</body>
注意:v-bind语法不支持驼峰命名法,要转成小写,例如childMyMessage要转成child-my-message才能使用v-bind
子组件中,通过$emit
来触发事件
父组件中,通过v-on
来监听事件
<body>
<!-- 父组件模板 -->
<div id="app">
<!-- 监听事件 v-on -->
<cpn @itemclick="cpnClick"></cpn>
</div>
<!-- 子组件模板 -->
<template id="cpn">
<div>
<button v-for="item in categories" @click="btnClick(item)">
{
{
item.name}}</button>
</div>
</template>
<script src="../vue.js"></script>
<script>
//子组件
const cpn = {
template: '#cpn',
data() {
return {
categories: [
{
id: '111', name: '热门' },
{
id: '222', name: '手机数码' },
{
id: '333', name: '家用' }
]
}
},
methods: {
btnClick(item) {
//发射事件:自定义事件
this.$emit('itemclick', item);
}
}
}
//父组件
const app = new Vue({
el: '#app',
data: {
},
components: {
cpn
},
methods: {
cpnClick(item) {
console.log(item);
}
}
})
</script>
</body>
$children
得到所有子组件,可以访问其中的属性和方法,但是对于获取第n个组件不那么方便
如:this.$children[0].showMessage();
$refs
得到的对应ref名字的组件,可以访问特定的子组件,用得较多
如:this.$refs.aaa.showMessage();
$parent
访问父组件,但是一般不适用,组件耦合度高,不方便复用
例如:this.$parent.name
$root
访问根组件,也很少用
例如:this.$root.name
slot的目的:更具有扩展性,抽取共性,保留不同
基本使用:
编译作用域
举个例子,当父组件和子组件都有数据(data)isShowed时,在父作用域下(e.g. id=“app”)使用的isShowed会在父组件中找,在子作用域下(id=“cpn”)使用的isShowed会在子组件中找
作用域插槽
父组件对子组件展示数据的方式不满意,拿到子组件的数据进行展示
<div id="app">
<cpn>cpn>
<cpn>
<temlate slot-scope="slot">
<span v-for="item in slot.data">{
{item}} - span>
temlate>
cpn>
<cpn>cpn>
div>
<template id="cpn">
<div>
<slot :data="pLanguages">
<ul>
<li v-for="item in pLanguages">{
{item}}li>
ul>
slot>
div>
template>
是为了解决多人开发下全局变量命名冲突的问题,还有js文件依赖的问题
常见的模块化规范:CommonJS、AMD、CMD、ES6的Modules