前言:常规问题
什么是组件:
- 组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可;
组件化和模块化的不同:
- 模块化: 是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一;
- 组件化: 是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用;
为什么组件中data必须是函数:
//伪代码
var Component = functionComponent() {};
Component.prototype.data = {
demo: 123
}
var component1 = new Component();
var component2 = new Component();
component1.data.demo = 456;
console.log(component2.data.demo); // 456
- 从上面可以看出,两个实例都引用同一个对象,其中一个改变的时候,另一个也发生改变。
- 每一个vue组件都是一个vue实例,通过new Vue()实例化,引用同一个对象,如果data直接是一个对象的话,那么一旦修改其中一个组件的数据,其他组件相同数据就会被改变。
- 而data是函数,并且在函数中return一个独立对象的时候,每个vue组件的data都因为函数有了自己的作用域,互不干扰。
一、组件使用
1.1 局部组件
- 创建页面组件
- 引用
1.2 全局组件
在src根目录下创建全局组件
然后在main.js下引入就行
import Item from '../components/Item.vue'
Vue.component("Item",Item)
二、组件传值
2.1 父组件传子组件
一、定义一个子组件
1.组件的名字是以大写字母开头的
2.驼峰命名
//1.components/HomeTable.vue
<template>
<div>
<div>
<span>name:张三</span>
<span>age:18</span>
</div>
</div>
</template>
<script>
export default {
name: "HomeTable"
};
</script>
<style>
</style>
二、在app.vue中导入子组件
<script>
//2.导入子组件
import HomeTable from './components/HomeTable'
export default {
name: 'app',
....
//3.需要在components属性中注册
components:{
HomeTable
}
}
</script>
//4.在模板中使用
<template>
<div id="app">
...
//可以使用下划线命名使用
<home-table ></home-table>
</div>
</template>
三、父组件向子组件传值
父组件:
//1.子组件通过属性接收父组件传递的参数
<home-table :data="arr"></home-table>
子组件:
//2.子组件接收的参数需要在props属性中注册
<script>
export default {
name: "HomeTable",
props: {
data: {
type: Array
}
}
};
</script>
- 传多个值的情况
```javascript
父组件:
子组件接收 props:{ data:{ type:Object, }, index:{ type:Number } }
父组件传子组件:<br />父组件:<br />![image.png](https://cdn.nlark.com/yuque/0/2019/png/402644/1574245567016-09702491-78a9-4afc-9147-4021222a0ae3.png#align=left&display=inline&height=537&name=image.png&originHeight=537&originWidth=652&size=41699&status=done&style=none&width=652)
子组件:<br />![image.png](https://cdn.nlark.com/yuque/0/2019/png/402644/1574245516907-fb16c902-ba7f-41b1-9272-be51b5c9bce4.png#align=left&display=inline&height=554&name=image.png&originHeight=554&originWidth=651&size=57838&status=done&style=none&width=651)
<a name="FNylQ"></a>
#### 四、子组件自定义事件向父组件传参
原理:父组件将方法的引用,传递到子组件内部,子组件在内部调用父组件传递过来的方法,同时把要发送给父组件的数据,在调用方法的时候当作参数传递进去;
```javascript
子组件:
//1.使用$emit方式自定义事件,向父组件传参
<button @click="handleDelete(index)">删除</button>
<script>
export default {
...
methods:{
handleDelete(index){
this.$emit("deleteItem",index)
}
}
};
</script>
父组件:
//2.父组件接收子组件传递过来的事件参数
<home-table :data="arr" @deleteItem="handleDelete"></home-table>
<script>
import HomeTable from './components/HomeTable'
export default {
name: 'app',
...
methods:{
handleDelete(index){
console.log(index)
}
}
}
</script>
2.2 跳转页面传id
第一种:页面直接跳转
第二种:子组件获取id 通过子组件自定义事件传参回父组件跳转
子组件
三、组件通讯
3.1 单向数据流
props
/$emit
父组件A通过props的方式向子组件B传递,B to A 通过在 B 组件中 $emit, A 组件中 v-on 的方式实现。
1.父组件向子组件传值
2.子组件向父组件传值(通过事件形式)
子组件通过this.$emit(“methodName”,data),父组件定义同名方法即可。
子组件定义
父组件接收
3.2 双向数据流
子组件
父组件
四、中央事件总线
中央事件总线 :
就是一个名字可以叫做Bus的vue空实例,里边没有任何内容。
它就像一个公交车一样,来回输送人,将组件A输送到组件B,再将组件B输送到组件A;
这里A,B组件可以是父、子组件,也可以是兄、弟组件,或者两个没有任何关系的组件;
我们可以使用中央事件总线这种技术来实现vue组件之间的数据通信。
//1.创建中央事件总线
var bus = new Vue();
//A组件发送
//2.使用Bus中央事件总线在A组件中发送信息
Bus.$emit('自定义事件名','$on发送过来的数据');
//B组件接收
//3.使用Bus中央事件总线在B组件中接收信息
Bus.$on('自定义事件名',function(){
//然后执行什么你自己懂的。。。
});
五、动态组件切换
//1.定义组件
//2.引入组件和data关联
<template>
<div>
<button @click="handleToggle">toggle</button>
<component :is="isToggle?one:two"></component>
</div>
</template>
<script>
import One from "../components/One.vue";
import Two from '../components/Two.vue'
export default {
data() {
return {
isToggle:false,
one: "One",
two:"Two"
};
},
components: {
One,
Two
},
methods:{
handleToggle(){
this.isToggle = !this.isToggle
}
}
};
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
<style>
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(150px);
}
.v-enter-active,
.v-leave-active {
transition: all 0.5s ease;
}
</style>
</head>
<body>
<div id="app">
<a href="" @click.prevent="comName='login'">登录</a>
<a href="" @click.prevent="comName='register'">注册</a>
<!-- Vue提供了 component ,来展示对应名称的组件 -->
<!-- component 是一个占位符, :is 属性,可以用来指定要展示的组件的名称 -->
<!-- 通过 mode 属性,设置组件切换时候的模式,out-in 表示原先的组件先出去,后来的组件再进来 -->
<transition mode="out-in">
<component :is="comName"></component>
</transition>
</div>
<script>
// 组件名称是 字符串
Vue.component('login', {
template: '<h3>登录组件</h3>'
})
Vue.component('register', {
template: '<h3>注册组件</h3>'
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
comName: 'login' // 当前 component 中的 :is 绑定的组件的名称
},
methods: {}
});
</script>
</body>
</html>