1 组件注册
步骤:
- 创建组件构造器
- 注册组件
- 使用组件
1.1 全局组件
用代码展示:
<div class="app">
<div><cpn1></cpn1></div>
</div>
<script src="../js/vue.js"></script>
<script>
// 1.创建组件构造器对象-------------------------------------------
const cpn = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈哈啊</p>
</div>`,
});
// 2.注册组件----------------------------------------
Vue.component('cpn1', cpn);
const app = new Vue({
el: '.app',
data: {},
});
</script>
全局组件语法糖写法:
<div class="app">
<div><cpn></cpn></div>
</div>
<script src="../js/vue.js"></script>
<script>
// 1.全局组件语法糖-------------------------------------------
Vue.component('cpn', {
template: `
<div>
<h2>我是标题1</h2>
<p>我是内容, 哈哈哈哈</p>
</div>`,
});
const app = new Vue({
el: '.app',
data: {},
});
</script>
1.2 局部组件
直接语法糖写法:
<div class="app">
<cpn></cpn>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '.app',
data: {},
components: {
cpn: {
template: `
<div>
<h2>我是标题2</h2>
<p>我是内容, 呵呵呵呵</p>
<cpn1></cpn1>
</div>
`,
},
},
});
</script>
注意Vue.component和局部组件中components,少了一个s
1.3 模板分离写法
template模板中内容太多时,用 语法书写较繁琐,所以可以将其分离到组件外面,两种写法:
<div class="app">
<cpn></cpn>
</div>
-------------------------------------------------第一种写法
<script type="text/x-template" id="cpn">
<div>
<h2>我是标题</h2>
<p>我是内容</p>
</div>
</script>
-------------------------------------------------第二种写法
<template id="cpn">
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈哈啊</p>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '.app',
data: {},
components: {
cpn: {
template: '#cpn',
},
},
});
</script>
组件data的注意事项:
- 组件不可以访问Vue实例中的数据
- 组件有其自身的data属性
- 组件的data属性必须是函数,且函数返回一个对象,对象内部保存着数据。原因:vue让每个组件对象都返回一个新的对象,如果是同一个对象,使用时会相互影响。
2 组件通信
2.1 父传子通信
通过props传递数据
<div class="app">
//将父组件即Vue实例中的数据传给子组件。
<cpn :cmovies="movies" :cstars="stars" :cstar="star"></cpn>
</div>
<template id="cpn">
<div>
<h2>我是子组件</h2>
//在子组件中使用
<h2>{{cmovies}}</h2>
<h2>{{cstar}}</h2>
<h2>{{cstars}}</h2>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return { message: '我是子组件里的数据' };
},
//通过props声明传输的数据,可以是数组形式
// props: ['cmovies', 'cstars', 'cstar'],
//也可以是对象形式
props: {
//可以限制类型,可以设置一些默认值
cstars: Array,
cstar: Object,
cmovies: {
type: [String, Array],
default: 'ccc',
require: true,
},
},
};
const app = new Vue({
el: '.app',
data: {
movies: '进击的巨人',
stars: ['德华', '学友', '福成', '明'],
star: { age: 18 },
},
components: {
cpn,
},
});
</script>
大概可以分为三步:
- 通过props声明传递的数据,以及设置一些数据限制
- 在子组件生成的标签中将父组件的数据通过v-bind传递给子组件
- 将数据应用在子组件中
2.2 子传父通信
通过$emit将自定义数据发射给父组件
<div class="app">
<cpn @m-click="cpnClick"></cpn>
</div>
<template id="cpn">
<div>
<button v-for="m in movies" @click="btnClick(m)">{{m}}</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return {
movies: ['烬', '目', '水', '或', '图'],
};
},
methods: {
btnClick(m) {
// 发射事件: 自定义事件
this.$emit('m-click', m);
},
},
};
const app = new Vue({
el: '.app',
date: {},
components: {
cpn,
},
methods: {
cpnClick(m) {
console.log('cpnClick', m);
},
},
});
</script>
当父组件将数据传输给子组件后,如果数据被操作后,需要将操作反馈给父组件,这时需要$emit()来触发事件,并将相应事件传给父组件,而父组件中通过v-on来监听子组件。
2.3 通信案例
通过v-model和父子间通信的原理实现,改变子组件的数据影响父组件的数据,形成一个循环,改变循环中的任何一个数据,所有数据都会随着改变。有点绕。
<div class="app">
<cpn
:number1="num1"
:number2="num2"
@num1change="number1change"
@num2change="number2change"
></cpn>
</div>
<template id="cpn">
<div>
<h2>props:{{number1}}</h2>
<h2>data:{{dnumber1}}</h2>
<input type="text" :vualue="dnumber1" @input="num1Input" />
<!-- <input type="text" v-model="dnumber1" /> -->
<h2>props:{{number2}}</h2>
<h2>data:{{dnumber2}}</h2>
<input type="text" :vualue="dnumber2" @input="num2Input" />
<!-- <input type="text" v-model="dnumber2" /> -->
</div>
</template>
<script src="../vue/js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return {
dnumber1: this.number1,
dnumber2: this.number2,
};
},
props: {
number1: Number,
number2: Number,
},
methods: {
num1Input(event) {
this.dnumber1 = event.target.value;
this.$emit('num1change', this.dnumber1);
this.dnumber2 = this.dnumber1 * 100;
this.$emit('num2change', this.dnumber2);
},
num2Input(event) {
this.dnumber2 = event.target.value;
this.$emit('num2change', this.dnumber2);
this.dnumber1 = this.dnumber2 / 100;
this.$emit('num1change', this.dnumber1);
},
},
};
const app = new Vue({
el: '.app',
data: {
num1: 1,
num2: 2,
},
components: {
cpn,
},
methods: {
number1change(value) {
this.num1 = parseInt(value);
},
number2change(value) {
this.num2 = parseInt(value);
},
},
});
</script>
通过watch监听也可以实现
<div class="app">
<cpn
:number1="num1"
:number2="num2"
@num1change="number1change"
@num2change="number2change"
></cpn>
</div>
<template id="cpn">
<div>
<h2>props:{{number1}}</h2>
<h2>data:{{dnumber1}}</h2>
<input type="text" v-model="dnumber1" />
<!-- <input type="text" v-model="dnumber1" /> -->
<h2>props:{{number2}}</h2>
<h2>data:{{dnumber2}}</h2>
<input type="text" v-model="dnumber2" />
<!-- <input type="text" v-model="dnumber2" /> -->
</div>
</template>
<script src="../vue/js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return {
dnumber1: this.number1,
dnumber2: this.number2,
};
},
props: {
number1: Number,
number2: Number,
},
watch: {
dnumber1(newValue) {
this.dnumber2 = newValue * 100;
this.$emit('num1change', newValue);
},
dnumber2(newValue) {
this.dnumber1 = newValue / 100;
this.$emit('num2change', newValue);
},
},
};
const app = new Vue({
el: '.app',
data: {
num1: 1,
num2: 2,
},
components: {
cpn,
},
methods: {
number1change(value) {
this.num1 = parseInt(value);
},
number2change(value) {
this.num2 = parseInt(value);
},
},
});
</script>
3 父子访问
3.1 父访问子
使用$children可以访问子组件,但$children生成的是一个数组,当子组件较多时,下标可能会改变。而$refs可以绑定在一个组件上,使用起来更方便。
<div class="app">
<cpn></cpn>
<cpn></cpn>
<cpn ref="aaa"></cpn>
<button @click="btnClick">按钮</button>
</div>
<template id="cpn">
<div><h2>我是子组件</h2></div>
</template>
<script src="js/vue.js"></script>
<script>
const app = new Vue({
el: '.app',
data: {},
methods: {
btnClick() {
// console.log('我是父组件的方法');
//第一种方法,通过$children,使用较少
// this.$children[0].showMessage();
// for (let i of this.$children) {
// console.log(i.name);
// }
//第二种方法,通过$refs,使用较多
console.log(this.$refs.aaa.name);
},
},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: '我是子组件的name',
};
},
methods: {
showMessage() {
console.log('我是子组件里的方法');
},
},
},
},
});
</script>
3.2 子访问父
root可以访问根组件
<div class="app">
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>我是子组件</h2>
<ccpn></ccpn>
</div>
</template>
<template id="ccpn">
<div>
<h2>我是子子组件</h2>
<button @click="btnClick">按钮</button>
</div>
</template>
<script src="js/vue.js"></script>
<script>
const app = new Vue({
el: '.app',
data: { message: '起飞' },
components: {
cpn: {
template: '#cpn',
components: {
ccpn: {
template: '#ccpn',
methods: {
btnClick() {
//1.访问父组件
console.log(this.$parent);
//2.访问根组件
console.log(this.$root);
},
},
},
},
},
},
});
</script>
4 slot
4.1 匿名slot
slot标签中可以有其他标签,使用子组件标签内部没有其他内容时,会将slot内部的内容显示出来,子组件标签内部有内容时会覆盖slot标签内容的内容。
<div class="app">
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>我是子组件</h2>
<slot><p>我是插槽</p></slot>
<slot>插槽</slot>
</div>
</template>
<script src="js/vue.js"></script>
<script>
const app = new Vue({
el: '.app',
data: {},
components: {
cpn: {
template: '#cpn',
},
},
});
</script>
4.2 具名slot
使用name属性标记子组件中的slot标签,可以有选择的使用插槽。
<div class="app">
<cpn><button slot="top">按钮</button></cpn>
</div>
<template id="cpn">
<div>
<slot name="top">
<h2>起飞</h2>
</slot>
<slot name="bottom"></slot>
</div>
</template>
<script src="js/vue.js"></script>
<script>
const app = new Vue({
el: '.app',
data: {},
components: {
cpn: {
template: '#cpn',
},
},
});
</script>
4.3 作用域插槽
通过slot-scope连接到子组件,然后调取子组件中的数据slot.data
<div class="app">
<cpn></cpn>
<cpn>
<template slot-scope="slot">
<!-- <span v-for="m in slot.data">{{m}}</span> -->
<span>{{slot.data.join('--')}}</span>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<slot :data="pLanguages">
<ul>
<li v-for="m in pLanguages">{{m}}</li>
</ul>
</slot>
</div>
</template>
<script src="js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return {
pLanguages: ['C', 'Java', 'C++', 'Go'],
};
},
};
const app = new Vue({
el: '.app',
data: {},
components: {
cpn,
},
});
</script>
接下来学习webpack