1. 认识组件化 1.1 什么是组件化 人面对复杂问题的处理方式 任何一个人处理信息的逻辑能力都是有限的,所以当面对一个非常复杂的问题时我们不太可能一次性搞定一大堆的内容。 但是我们人有一种天生的能力
1. 认识组件化
1.1 什么是组件化
1.2 Vue组件化思想
2. 注册组件
2.1 注册组件的基本步骤
-
- 调用
Vue.extend()
创建的是一个组件构造器
- 通常在创建组件构造器时,传入template代表我们自定义组件的模板
- 该模板就是在使用到组件的地方要显示的HTML代码
- 事实上,这种写法在
Vue2.x
的文档中几乎已经看不到了,它会直接使用下面如 2.4 形式的语法糖,但是在很多资料还是会提到这种方式,而且这种方式是学习后面方式的基础
-
- 调用
Vue.component()
是将刚才的组件构造器注册为一个组件并且给它起一个组件的标签名称
- 所以需要传递两个参数:① 注册组件的标签名 ② 组件构造器
-
- 组件必须挂载在某个Vue实例下,否则它不会生效
- 下面我使用了三次
<my-cpn></my-cpn>
,而第三次其实并没有生效
2.2 组件的作用域
2.3 父子组件
2.4 注册组件语法糖
3. 组件其他补充
3.1 模板的分离写法
- 使用
<script>
标签
- 使用
<template>
标签
3.2 组件可以访问Vue的实例数据吗?
- 如下测试发现不能并不能访问,而且即使可以访问,如果将所有的数据都放在Vue实例中Vue实例就会变的非常臃肿
- 结论:组件并不能直接访问Vue实例中的data,Vue组件应该有自己保存数据的地方
3.3 组件数据的存放
4. 父子组件通信
4.1 父子组件通信理解
-
-
-
-
- 通过
props
向子组件传递数据
- 通过
事件
向父组件发送消息
4.2 父组件向子组件传递数据 - props
- 字符串数组,数组中的字符串就是传递时的名称
- 对象,对象可以设置传递时的类型,也可以设置默认值等
- String
- Number
- Boolean
- Array
- Object
- Date
- Function
- Symbol
4.4 子组件向父组件传递数据或事件 - $emit()
- 我们之前做过一个两个按钮
+1
和 -1
,点击后修改 counter
- 我们整个操作的过程还是在子组件中完成,但是之后的展示交给父组件
- 这样我们就需要将子组件中的
counter
,传给父组件的某个属性比如 total
4.5 父子传参与双向绑定结合的案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<cpn
:snum1="num1"
:snum2="num2"
@num1-exchange="setNum1"
@num2-exchange="setNum2"
></cpn>
</div>
<template id="temp1">
<!-- 1.下面的写法是有问题的,我们应该避免在子组件中直接修改props中的值
<div>
<span>props: {{snum1}}</span>
<input type="text" v-model="sNum1">
<hr>
<span>props: {{snum2}}</span>
<input type="text" v-model="sNum2">
</div>
-->
<!-- 2.这种方式双向绑定是可行的,但是我们想在input变化时同时父组件的num值也发生变化,怎么实现呢?
<div>
<span>props: {{snum1}}</span>
<span>data: {{number1}}</span>
<input type="text" v-model="number1">
<hr>
<span>props: {{snum2}}</span>
<span>data: {{number2}}</span>
<input type="text" v-model="number2">
</div>
-->
<!--
3. v-model包含两个操作即:value与@input,我们可以通过分解v-model来绑定事件,从而实现双向绑定子传父的功能
-->
<div>
<span>props: {{snum1}}</span>
<span>data: {{number1}}</span>
<input type="text" :value="number1" @input="number1Input">
<hr>
<span>props: {{snum2}}</span>
<span>data: {{number2}}</span>
<input type="text" :value="number2" @input="number2Input">
</div>
<!--
4. 我们也可以通过watch属性来实现,后面会讲watch
-->
</template>
<script>
const vue = new Vue({
el: '#app',data() {
return {
num1: '',num2: ''
}
},methods: {
setNum1(val) {
this.num1 = val;
console.log(this.num1);
},setNum2(val) {
this.num2 = val;
}
},components: {
cpn: {
template: temp1,props: {
snum1: {
type: String,default: () => { return '' }
},snum2: {
type: String,default: () => { return '' }
}
},data(){
return {
number1: this.sNum1,number2: this.sNum2
}
},methods: {
number1Input(event){
this.number1 = event.target.value;
this.$emit('num1-exchange',this.number1);
},number2Input(event){
this.number2 = event.target.value;
this.$emit('num2-exchange',this.number2);
}
}
}
}
})
</script>
</body>
</html>
4.6 父子组件的直接访问方式 - $children或$refs / $parent
5. 非父子组件通信
5.1 理解
- 但是这种方案和直接使用
Vuex
的状态管理方案还是逊色很多
- 并且
Vuex
提供了更多好用的功能,所以这里我们暂且不讨论这种方案,后续我们专门学习 Vuex
的状态管理
5.2 中央事件总线
5.3 Vuex状态管理(后面专门讲)
6. 插槽slot
6.1 编译作用域
- 官方给出了一条准则:父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译
- 而我们在使用
<my-cpn v-show="isShow"></my-cpn>
的时候,整个组件的使用过程是相当于在父组件中出现的
- 那么他的作用域就是父组件,使用的属性也是属于父组件的属性
- 因此 isShow使用的是Vue实例中的属性,而不是子组件的属性
6.2 为什么使用slot
6.3 如何在封装组件时正确使用slot
6.4 slot基本使用
-
<slot>
中的内容表示,如果没有在该组件中插入任何其他内容,就默认显示该内容
- 有了这个插槽后,父组件如何使用呢?
6.5 具名插槽slot
6.6 作用域插槽
- 某些界面是以水平方向一一展示的,
- 某些界面是以列表形式展示的,
- 某些界面直接展示一个数组