03组件化开发父子组件通信
Posted shawnyue-08
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了03组件化开发父子组件通信相关的知识,希望对你有一定的参考价值。
目录
组件化开发
组件化的基本使用过程
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈哈哈</p>
<p>我是内容,哈哈哈哈哈</p>
<h2>我是标题</h2>
<p>我是内容,哈哈哈哈哈</p>
<p>我是内容,哈哈哈哈哈</p>
<h2>我是标题</h2>
<p>我是内容,哈哈哈哈哈</p>
<p>我是内容,哈哈哈哈哈</p>
<h2>我是标题</h2>
<p>我是内容,哈哈哈哈哈</p>
<p>我是内容,哈哈哈哈哈</p>
</div>
<script src="../js/vue.js"></script>
<script>
</script>
</body>
</html>
容易造成大量重复性代码,所以需要把页面中需要多次使用的代码提取出来,作为一个组件(Component)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!-- 组件必须挂载在某个实例下,否则不会生效 -->
<my-component></my-component>
<div>
<my-component></my-component>
</div>
</div>
<!-- 不会生效 -->
<my-component></my-component>
<script src="../js/vue.js"></script>
<script>
//1、创建一个组件构造器对象
const component = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈哈哈</p>
<p>我是内容,哈哈哈哈哈</p>
</div>`
/* template:自定义组件的模板 */
/* ES6新增一种字符串的表示方式,``,优点在于可以换行 */
});
//2、注册组件
Vue.component(‘my-component‘, component);
const app = new Vue({
el: ‘#app‘,
data: {
}
})
</script>
</body>
</html>
事实上,这种写法在Vue 2.x的文档中几乎已经看不到了,他会直接使用我们下面的语法糖。
全局组件和局部组件
全局组件:可以在多个Vue的实例下使用;
局部组件:在哪个Vue实例下注册,就只能在哪个Vue实例绑定的组件中使用。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<my-component></my-component>
<demo></demo>
</div>
<!-- 全局组件:可以在多个Vue实例下使用 -->
<div id="test">
<my-component></my-component>
<!-- 在app的Vue实例下注册的局部组件,不能在test中使用 -->
<demo></demo>
</div>
<script src="../js/vue.js"></script>
<script>
const component = Vue.extend({
template: `
<div>
<h2>全局组件的标题</h2>
<p>我是内容,哈哈哈哈</p>
<p>我是内容,哈哈哈哈</p>
</div>
`
});
//2、注册组件(全局组件)
Vue.component(‘my-component‘, component);
const demo = Vue.extend({
template: `
<div>
<h2>局部组件的标题</h2>
<p>我是内容,嘻嘻嘻嘻</p>
<p>我是内容,嘻嘻嘻嘻</p>
</div>
`
});
const app = new Vue({
el: ‘#app‘,
components: {
/* 注册局部组件,在某个Vue实例下注册,只能在该实例绑定的组件下使用 */
‘demo‘: demo
}
});
const test = new Vue({
el: ‘#test‘
});
</script>
</body>
</html>
注册组件的语法糖写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<component1></component1>
<my-component></my-component>
</div>
<script src="../js/vue.js"></script>
<script>
//全局组件注册的语法糖
Vue.component(‘component1‘,{
template: `
<div>
<h2>我是全局组件的标题</h2>
<p>我是内容,哈哈哈哈</p>
</div>
`
});
const app = new Vue({
el: ‘#app‘,
components: {
//局部组件注册的语法糖
‘my-component‘: {
template: `
<div>
<h2>我是局部组件的标题</h2>
<p>我是内容,呵呵呵呵</p>
</div>
`
}
}
})
</script>
</body>
</html>
组件模板抽离的写法
在组件中写template模板的HTML代码是一件十分麻烦的事,特别不方便。
Vue提供了两种方案写HTML代码
- 使用script标签(不常用)
- 使用template标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<my-component></my-component>
</div>
<!-- 使用template标签 -->
<template id="my-component-template">
<div>
<h2>我是全局组件的标题</h2>
<p>我是内容,哈哈哈哈</p>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
/* 注册全局组件:组件与模板分离 */
Vue.component(‘my-component‘, {
template: ‘#my-component-template‘,
});
const app = new Vue({
el: ‘#app‘,
})
</script>
</body>
</html>
组件的数据存放问题
组件可以访问Vue实例的数据吗?
- 组件内部不能访问Vue实例中的数据
Vue组件应该有自己保存数据的地方。
组件有一个data属性,(必须是一个函数),这个函数返回一个对象,对象内部保存着数据。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<my-component></my-component>
</div>
<template id="my-component-template">
<div>
<span>{{message}}</span>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
Vue.component(‘my-component‘, {
template: ‘#my-component-template‘,
data() {
return {
message: ‘Hello Vue.js‘,
}
}
})
const app = new Vue({
el: ‘#app‘,
data: {
}
})
</script>
</body>
</html>
组件中的data为什么是函数?
单个页面复用一个组件时,组件的data域就不能是属性了,不然修改一个组件,其他组件都跟着变化。
把计数器封装为一个组件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<my-counter></my-counter>
<hr>
<my-counter></my-counter>
<hr>
<my-counter></my-counter>
</div>
<template id="my-counter-template">
<div>
<h3>当前计数:{{counter}}</h3>
<button v-on:click="increment">+</button>
<button v-on:click="decrement">-</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
Vue.component(‘my-counter‘, {
template: ‘#my-counter-template‘,
data() {
return {
counter: 0
}
},
methods: {
increment() {
this.counter++;
},
decrement() {
this.counter--;
}
}
})
const app = new Vue({
el: ‘#app‘,
data: {}
})
</script>
</body>
</html>
组件通信
父子通信父传子
Vue官方提供的父子组件通信方式
- 通过props向子组件传递数据
- 通过事件向父组件发送消息
在下面的代码中,直接将Vue实例作为父组件,并且其中包含子组件来简化代码。
props的值有两种方式:
- 字符串数组:数组中的字符串就是传递时的名称(id);
- 对象:功能丰富,常用
props是数组类型
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!-- 子组件不能直接使用父组件/Vue实例的数据,可以通过Vue实例/父组件向子组件通信的方式来传递数据 -->
<my-component-son v-bind:books="books" v-bind:message="message"></my-component-son>
</div>
<template id="my-component-son-template">
<div>
<ul>
<li v-for="item in books">{{item}}</li>
</ul>
<span>{{message}}</span>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: ‘#app‘,
data: {
message: ‘你好啊‘,
books: [‘三体‘, ‘平凡的世界‘, ‘春‘, ‘白夜行‘]
},
components: {
‘my-component-son‘: {
template: ‘#my-component-son-template‘,
data() {
return {
}
},
/* props是一个字符串数组 */
props: [‘books‘, ‘message‘]
}
}
})
</script>
</body>
</html>
props是对象类型
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!-- 没有绑定number,显示默认值1 -->
<my-component-son v-bind:books="books" :message="message"></my-component-son>
</div>
<template id="my-component-son-template">
<div>
<ul>
<li v-for="item in books">{{item}}</li>
</ul>
<span>{{message}}</span>
<span>{{number}}</span>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: ‘#app‘,
data: {
message: ‘你好啊‘,
books: [‘三体‘, ‘解忧杂货铺‘, ‘白夜行‘, ‘时间简史‘],
number: 100,
},
components: {
‘my-component-son‘: {
template: ‘#my-component-son-template‘,
/* props是对象,可以指定变量的类型,并且提供默认值 */
props: {
/*books: Array,
message: String,
number: Number,*/
books: {
type: Array,
/* 对象或数组默认值必须从一个工厂函数获取 */
default() {
return [];
},
required: true
},
message: {
type: String,
default: ‘‘,
required: true
},
number: {
type: Number,
default: 1,
required: false
}
}
}
}
})
</script>
</body>
</html>
props驼峰标识
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!-- son-info -->
<my-component-son v-bind:son-info="info"></my-component-son>
</div>
<template id="my-component-son-template">
<div>
<ul>
<!-- sonInfo -->
<li v-for="(value, key, index) in sonInfo">{{index + 1}}---{{key}}:{{value}}</li>
</ul>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: ‘#app‘,
data: {
info: {
name: ‘张三‘,
age: 22,
gender: ‘男‘
}
},
components: {
‘my-component-son‘: {
template: ‘#my-component-son-template‘,
props: {
/* sonInfo */
sonInfo: {
type: Object,
default() {
return {};
},
required: true
}
}
}
}
})
</script>
</body>
</html>
父子通信子传父
Vue官方提供的父子组件通信方式
- 通过props向子组件传递数据
- 通过事件向父组件发送消息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!-- v-on监听自定义事件,cpnClick不传递参数默认会把item传递到父组件 -->
<my-component-son v-on:item-click="cpnClick"></my-component-son>
</div>
<template id="my-component-son-template">
<div>
<button v-for="item in categories" v-on:click="btnClick(item)">{{item.name}}</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: ‘#app‘,
components: {
‘my-component-son‘: {
template: ‘#my-component-son-template‘,
data() {
return {
categories: [
{
id: 1,
name: ‘家用电器‘
},
{
id: 2,
name: ‘手机通讯‘
},
{
id: 3,
name: ‘电脑办公‘
}
],
}
},
methods: {
btnClick(item) {
/* 子组件发射事件,事件类型自定义为‘item-click‘ */
this.$emit(‘item-click‘, item);
}
}
}
},
methods: {
/* 调用时没有传递参数,以前默认传递event,这里传递item */
cpnClick(item) {
console.log(‘cpnClick‘, item);
}
}
});
</script>
</body>
</html>
父子组件通信结合表单的双向绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<my-component v-bind:number1="num1" :number2="num2"
v-on:n1change="num1change" v-on:n2change="num2change"></my-component>
</div>
<template id="my-component-template">
<div>
<span>props:{{number1}}</span>
<span>data:{{n1}}</span>
<input type="number" id="n1" v-model.number="n1">
<label for="n1"></label>
<br>
<span>props:{{number2}}</span>
<span>data:{{n2}}</span>
<input type="number" id="n2" v-model.number="n2">
<label for="n2"></label>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: ‘#app‘,
data: {
num1: 1,
num2: 0,
},
components: {
‘my-component‘: {
template: ‘#my-component-template‘,
props: {
number1: {type: Number},
number2: {type: Number},
},
data() {
return {
n1: this.number1,
n2: this.number2
}
},
watch: {
n1(newValue) {
//n1修改,n2=n1*100
this.n2 = newValue * 100;
this.$emit(‘n1change‘, newValue);
this.$emit(‘n2change‘, this.n2);
},
n2(newValue) {
//n2修改,n1=1/100*n2
this.n1 = 1/100 * newValue;
this.$emit(‘n2change‘, newValue);
this.$emit(‘n1change‘, this.n1);
}
}
}
},
methods: {
num1change(value) {
this.num1 = parseInt(value);
},
num2change(value) {
this.num2 = parseInt(value);
}
}
})
</script>
</body>
</html>
注意点:
1、template标签,一定要有一个根标签;
2、组件的data必须是一个函数;
3、组件的props最好用对象;
4、组件绑定模板用#。
父访问子
父组件访问子组件:$children
或者$refs
。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!-- ref在实际开发中用的很多 -->
<my-component-1 ref="one"></my-component-1>
<my-component-1 ref="two"></my-component-1>
<my-component-1 ref="three"></my-component-1>
<button v-on:click="btnClick">按钮</button>
</div>
<template id="my-component-1-template">
<div>
<span>我是子组件1号</span>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: ‘#app‘,
data: {
},
components: {
‘my-component-1‘: {
template: ‘#my-component-1-template‘,
methods: {
showMessage() {
console.log(‘showMessage‘);
}
},
data() {
return {
name: ‘Hello Vue.js‘
}
}
}
},
methods: {
btnClick() {
/*
this.$children不常使用
for (let item of this.$children) {
item.showMessage();
console.log(item.name);
}
*/
console.log(this.$refs.three.name);
//Hello Vue.js
}
}
})
</script>
</body>
</html>
子访问父
子组件访问父组件:$parent
。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<my-component></my-component>
</div>
<template id="my-component-template">
<div>
<span>我是子组件</span>
<button v-on:click="btnClick">按钮</button>
<my-component-son></my-component-son>
</div>
</template>
<template id="my-component-son-template">
<div>
<span>我是子组件的子组件</span>
<button v-on:click="btnClick">按钮</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: ‘#app‘,
data: {
message: ‘你好a‘
},
components: {
‘my-component‘: {
template: ‘#my-component-template‘,
methods: {
btnClick() {
console.log(this.$parent);
}
},
data() {
return {
name: ‘我是my-component组件的name‘
}
},
components: {
‘my-component-son‘: {
template: ‘#my-component-son-template‘,
methods: {
btnClick() {
/* 访问父组件 */
console.log(this.$parent);
console.log(this.$parent.name);
/* 访问根组件 */
console.log(this.$root);
console.log(this.$root.message);
}
}
}
}
}
}
})
</script>
</body>
</html>
以上是关于03组件化开发父子组件通信的主要内容,如果未能解决你的问题,请参考以下文章