Vue 父子组件通信
@
目录
一. Vue的组件化开发实现
- 任何一个应用都可以抽象成一颗组件树
- 组件里面可以再包含组件,每个组件也可以有自己的内容
二. 注册组件的基本步骤
- 创建组件构造器
- 注册组件 (全局注册,局部注册)
- 使用组件
三.组件的基本使用过程
组件化开发是用来解决什么问题的?
比如下边一块代码,我想把它在多个地方重复使用,那么怎么用呢?就是他抽象化为一个组件。
<div>
<h1>找是个标题</h1>
<p>今天天气真的不错</p>
<p>哈哈。今天好开心</p>
</div>
根据步骤:写代码:
<body>
<div id="app">
<my-cpn></my-cpn>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
//构建组件构造函数
const cpnC = Vue.extend({
template: `
<div>
<h1>找是个标题</h1>
<p>今天天气真的不错</p>
<p>哈哈。今天好开心</p>
</div>`
})
//注册组件
//第一个参数是要使用的组件的名字,第二个是组件的模板名字
Vue.component("my-cpn",cpnC)
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
},)
//使用组件
</script>
</body>
效果图:
Vue可以进行嵌套使用,但是必须要挂载到一个 vue 的实例里面才行,写外边不行。:
3.局部组件和全局组件
刚刚注册的那种方式就是一个全局组件,可以在任何 Vue 实例中都可以进行使用,如何创建局部组件呢?
其实就是可以在某个vue实例中注册就可以了
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components:{ //只能在一个实例中注册使用
my_cpn:cpnC
}
},)
四. 父子组件
就是在一个组件里面嵌套一个组件:如果是在嵌套的里面注册的,那么只能在嵌套的里面使用。
<body>
<div id="app">
<my_cpn></my_cpn>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
//构建组件构造函数
const cpnC1 = Vue.extend({
template: `
<div>
<h1>我是标题1</h1>
<p>今天天气真的不错,哈哈</p>
</div>`
})
const cpnC2 = Vue.extend({
template: `
<div>
<h1>我是标题2</h1>
<p>今天天气真的不错,呵呵</p>
<cpnC1></cpnC1>
</div>`,
components: {
cpnC1: cpnC1
}
})
//注册组件
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
my_cpn: cpnC2
}
}, )
//使用组件
</script>
</body>
五.注册组件语法糖
<body>
<div id="app">
<cpn1></cpn1> 全局语法糖注册
<cpn2></cpn2> 局部语法糖注册
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
//语法糖全局注册
Vue.component('cpn1',{
template: `
<div>
<h1>我是标题1</h1>
<p>今天天气真的不错,哈哈</p>
</div>`
})
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
//组件局部注册的语法糖
components: {
"cpn2":{
template:`
<div>
<h1>我是标题2</h1>
<p>今天天气真的不错,呵呵</p>
</div>`
}
}
}, )
//使用组件
</script>
</body>
六. 组件模板抽离的写法
在上边的模板中写,多多少少的有点乱,因为在 templata 的模板里,你写了 html5 的文件,所以最好的方法,是把 html5的部分,抽象出来
使用 <template>
标签进行抽象:然后通过id
进行连接
<template id="cpn">
<div>
<h1>我是标题1</h1>
<p>我是内容一</p>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
//语法糖全局注册
Vue.component('cpn1',{
template:'#cpn' // 通过此处与上边 template 联系起来
})
七. 为啥 data() 一定要是函数?
其实就是解决,用 template 不能直接访问 Vue 里面的数据,他只能访问template 自己里面的数据。
<body>
<div id="app">
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<template id="cpn">
<div>
<h1>我是标题1</h1>
<p>我是内容一</p>
<p>{{title}}</p>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
//语法糖全局注册
Vue.component('cpn1', {
template: '#cpn', // 通过此处与上边 template 联系起来
data(){
return{
title:'abc'
}},
methods: {
},
})
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
</body>
效果图:
八.父子组件的通信
- 通过 props 向子组件传递数据
- 通过事件向父组件发送消息
8.1父->子组件通信
<div id="app">
<cpn v-bind:cmovies="movies" :cmessage="message"></cpn>
<p>正常</p>
</div>
<!-- 定义一个组件 -->
<template id="cpn">
<div>
<h1>标题</h1>
<p>{{cmovies}}</p>
<p>{{cmessage}}</p>
<p>{{cmessages}}</p>
<ul>
<li v-for="item in cmovies">{{item}}</li>
</ul>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const cpn = {
template: "#cpn",
// 普通的传值写法
// props: ['cmovies','cmessage'],
props:{
cmovies:Array, //直接指名传输的数据类型
cmessage:{
type:String, // 除了指定传输类型以外,还可以指定默认值。
default:"暂时没有传值",
},
cmessages:{
type:String,
default:"暂时没有传值",
//required:true //这个就是默认的必须要传递的,不穿的话会有错误。
}
},
data() {
return {
}
},}
const app = new Vue({
el: '#app',
data: {
message: "你好啊",
movies: ["海王", "海贼王", "海尔兄弟"]
},
components: {
// 当组件的原名和要命的名重合,就可以这样简写
cpn
}
})
</script>
效果图:
props的通信的类型
目前Vue 中不支持驼峰的命名方式:
使用类型传值(可以使用这种方法把父组件的data 里的东西提出来);
// 往子组件传东西
props: {
cmonte: Array,
wwe: String,
message:{
type:String,
default:"aaaa",
}
},
父传子的第二个例子:
我们用的最多方式,可以通过Prop向子组件传递数据。
用一个形象的比喻来说,父子组件之间的数据传递相当于自上而下的下水管子,只能从上往下流,不能逆流。这也正是Vue的设计理念之单向数据流。而Prop正是管道和管道之间的一个衔接口,这样(水)数据才能向下流.
<div id="app">
<counter :count='1'></counter>
<counter :count='2'></counter>
</div>
<script>
Vue.component('counter', {
props: ['count'], // 声明组件的时候,就声明这样一个props。
data: function () {
return {
number: this.count
}
},
template: '<div @click="add">{{number}}----{{count}}</div>', // 后面当自己组件的用
methods: {
add: function () {
this.number++;
}
},
})
let vm = new Vue({
el: "#app",
})
</script>
父子通信的参考资料 https://blog.csdn.net/qq_37288477/article/details/86630428
8.2子--> 父组件通信
子组件往父组件通信,更多的是传递的事件,比如手机导航栏,点击以后,应该给,在另一个显示组件里进行不同的显示。
<body>
<!-- 父组件模板 -->
<div id='app'>
<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="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
// 子组件
const cpn = {
template: '#cpn',
data() {
return {
categories: [{
id: 'aaa',
name: '热门推荐'
},
{
id: 'aaa',
name: '手机数码'
},
{
id: 'aaa',
name: '家用家电'
},
{
id: 'aaa',
name: '电脑办公'
},
]
}
},
methods: {
btnClick(item) {
console.log(item);
// 把这个事件发送出去
// 都不要使用驼峰的写法
// 自定义事件
this.$emit('itemclick',item) //(事件名和参数)
}
},
}
// 父组件
const app = new Vue({
el: '#app',
data: {
message: "你好啊",
movies: ["海王", "海贼王", "海尔兄弟"]
},
components: {
// 当组件的原名和要命的名重合,就可以这样简写
cpn
},
methods:{
cpnclick(item){
console.log("00cpnclick",item.name)
}
}})
</script>
</body>