Vue系统学习:4、组件化开发
1、组件文档链接:https://www.jianshu.com/p/29c514ef3462
1、全局组件和局部组件:
<div id="app">
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<my-cpn2></my-cpn2>
</div>
<script src="../js/vue.js"></script>
<script>
// 1、全局组件
// Vue.component(组件名称,{
// data: 组件数据,
// template: 组件模板内容
// })
Vue.component('my-cpn', {
data: () => {
return { count: 0 }
},
template: `<button @click='handle'>点击了{{count}}次</button>`,
methods: {
handle() {
this.count += 2;
}
}
})
const app = new Vue({
el: '#app',
// 2、局部组件
components: {
'my-cpn2': {
template: `<h2>Hello Word</h2>`,
}
}
})
</script>
1.1、HTML代码抽离方法:
<template id="my-cpn">
<div>
<button>点我</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
Vue.component('my-cpn', {
template: '#my-cpn',
})
父组件和子组件及其类型,差别只在于子组件没有el挂载点,
取而代之的是 template属性,其余方法几乎是一样的。
<div id="app"> // 父组件绑定 app </div> <template id="cpn"> // 子组件绑定cpn <div> </div> </template> <script src="../js/vue.js"></script> <script> const cpn = { // 父子组件里面结构几乎一样 template: '#cpn', data() { return { } }, methods: { }, } const app = new Vue({ el: '#app', data: {}, methods: { }, components: { cpn } }) </script>
父组件和子组件:
①、父组件必须注册子组件。
②、父子组件模板之间只能使用自己组件的数据,不能直接互相使用。
③、父组件和子组件及其类型,差别只在于子组件没有el挂载点,取而代之的是 template属性,其余方法几乎是一样的。
2、父子组件之间的通信:父--->子:props
①、在子组件中使用props接收父组件data数据:子组件定义一个新变量接收数据。
②、字父组件模板中绑定父组件data数据:新变量绑定父组件data里面的变量。
③、在子组件模板中直接使用父组件模板中绑定的数据:子模板中使用绑定了父组件内容的新变量。
2、父子组件的通信:子--->父:$emit():
①、子组件通过$emit('事件名称', 事件参数),将事件发送出去:
this.$emit('sonclick', item)
②、父组件模板监听子组件发送出来的事件:
<cpn @sonclick='fatherclick'></cpn>
③、去父组件中定义这个方法
总的来说:首先:子组件用$emit方法将事件传递出去,而父组件则在父组件模板里面监听这个发送的事件,然后在父组件里面定义这个事件。
<!--父模板-->
<div id="app">
<!--接收子组件发送的事件-->
<cpn @sonclick='fatherclick'></cpn>
</div>
<!-- // 子模板 -->
<template id="cpn">
<div>
<button v-for='item in cate' @click='btnclick(item)'>{{item.name}}</button>
</div>
</template>
<body>
<script src="../js/vue.js"></script>
<script>
// 1、子组件:在子组件中通过$emit()来触发事件
const cpn = {
template: '#cpn',
data() {
return {
cate: [
{ id: '1', name: '热门推荐' },
{ id: '2', name: '手机数码' },
{ id: '3', name: '家用家电' },
{ id: '4', name: '电脑办公' },
]
}
},
methods: {
btnclick(item) {
// emit发射事件:自定义事件(事件名称,事件参数)
this.$emit('sonclick', item)
}
}
}
// 2、父组件
new Vue({
el: '#app',
components: { cpn },
methods: {
fatherclick(item) {
console.log('hello', item);
}
},
})
</script>
③、父子组件相互传递:
<div id="app">
<cpn :sonnum='fathernum'></cpn>
</div>
<template id="cpn">
<div>
<ul>
<li v-for='item in sonnum'>{{item}}</li>
</ul>
<button v-for='(it,index) in city'>{{city[index]}}</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 父组件
new Vue({
el: '#app',
data: {
fathernum: [12, 22, 32, 42]
},
methods: {
fatherclick(it) {
console.log(it);
}
},
// 子组件
components: {
cpn: {
template: '#cpn',
props: {
sonnum: {
type: Array
}
},
data() {
return {
city: ['北京', '上海', '广州', '深圳']
}
},
methods: {
btnclick(item) {
this.$emit('sonclick', item)
}
},
}
}
})
</script>
1、父组件访问子组件:ref
<div id="app">
<cpn ref="reference"></cpn>
<button @click='refclick'>点我</button>
</div>
<template id="cpn">
<div>
<h2>我是子组件</h2>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
},
methods: {
refclick() {
// $refs是一个对象类型,默认是一个空对象,只有传了一个变量之后才会拿到子组件内容
console.log(this.$refs.reference.name);
}
},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: '我是子组件的name'
}
},
methods: {
btnclick(item) {
this.$emit('sonclick', item)
}
},
}
}
})
</script>
二、组件插槽:slot
①、定义:为了让封装的组件更加具有扩展性。
②、就是在组件模板中预留一个空间,让使用者决定组件内部的一些内容到底展示什么。
1、具名插槽:给插槽起一个名字
<div id="app">
<cpn>
<span slot="left">替换左按钮</span>
<!-- <i>我是i</i>
<em>我是em</em> -->
</cpn>
<!-- <cpn><i slot="right">替换右按钮</i></cpn> -->
</div>
<template id="cpn">
<div>
<slot name='left'><button>左按钮</button></slot>
<slot name='middle'><button>中间按钮</button></slot>
<slot name='right'><button>右按钮</button></slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
new Vue({
el: '#app',
components: {
cpn: {
template: '#cpn'
}
}
})
</script>
2、作用域插槽:父组件替换插槽的标签,但是内容是由子组件来提供。
①、什么是组件作用域:说白了就是父组件模板不可以使用子组件数据;子组件模板不可以使用父组件数据。
a、父组件模板的所有东西都会在父级作用域(父组件)内编译;
b、子组件模板所有东西都会在子级作用域(子组件)内编译。
②、那么如何解决这个插槽不能相互使用的问题呢?
<div id="app">
<cpn></cpn>
<cpn>
<!-- // 目的是获取子组件中的plaguanges数据 -->
<template v-slot:slot>
<div>
<span>{{slot.data}}-</span>
</div>
</template>
</cpn>
<cpn>
<template v-slot:slot>
<div>
<span v-for="item in slot.data">{{item}} *</span>
</div>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<!-- data这个名字是自己定义的 -->
<slot :data='planguanges'>
<ul>
<li v-for='item in planguanges'>{{item}}</li>
</ul>
</slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
new Vue({
el: '#app',
components: {
cpn: {
template: '#cpn',
data() {
return {
planguanges: ['js', 'java', 'node', 'c++', 'c#']
}
},
}
}
})
</script>