Vue学习之认识到应用(二)

上一篇写到了三万多字,打字都要延迟好一会,现在能实时显示文字,感觉好丝滑哈哈。

目录

8.Vue组件化 - 父子组件间通信

8.1.父组件传递给子组件

8.1.1.props的数组用法

8.1.2.props的对象用法

8.1.3.attribute继承

8.2.子组件传递给父组件

8.2.1.emit属性

9.Vue组件化 -  插槽Slot

9.1.slot的基本使用 

9.2.slot的默认内容

9.3.多个插槽的效果

9.4.具名插槽的使用

9.5. 动态插槽名(了解)

9.6.具名插槽的语法糖

9.7.作用域插槽(重要)

10.Vue组件化 - 非父子组件通信

10.1. Provide和Inject

10.2. Provide和Inject的函数写法

11.Vue组件化 - 额外知识补充

11.1.组件的生命周期

11.1.1.组件生命周期演练 

11.2.组件中的ref引用

11.3.动态组件的使用

11.3.1.用v-if显示不同组件 

11.3.2.动态组件的实现

11.4.keep-alive的使用

11.4.1. keep-alive属性

11.4.2.缓存组件的生命周期

11.5.Webpack的代码分包

11.5.1.Vue中实现异步组件

11.6.组件的v-model

11.7.Mixin的使用

11.7.1.Mixin的合并规则

11.7.2.全局混入Mixin 

12.Vue3 - CompositionAPI

12.1.认识Composition API 

12.2.setup函数的参数 

12.3.setup函数的返回值

12.4.Reactive API

12.5.Ref API(重要) 

12.6.认识readonly

12.6.1.readonly的使用

12.7.Reactive判断的API(了解)

12.8.toRefs(了解)

12.9.toRef(了解)

12.10.ref其他的API

12.11.computed计算属性

12.12.setup中ref的使用

12.13.setup函数中的生命周期

12.14.Provide函数和Inject函数

12.14.1.provide函数

12.14.2.Inject函数

12.15. watch侦听数据

12.15.1.watch的使用

12.15.2.watch的选项

12.15.3.watchEffect

12.15.4.watchEffect停止侦听

 12.16.script setup语法

12.16.1.顶层的绑定会暴露给模板

12.16.2.导入的组件直接使用

12.16.3.defineProps()和defineEmits()

12.16.4. defineExpose()


如果有什么不懂的可以查Vue.js官网

8.Vue组件化 - 父子组件间通信

前面的组件化基础中是将所有的逻辑放到一个App.vue中:
  • 在之前的案例中,我们只是创建了一个组件App
  • 如果我们一个应用程序将所有的逻辑都放在一个组件中,那么这个组件就会变成非常的臃肿和难以维护
  • 所以组件化的核心思想应该是对组件进行拆分,拆分成一个个小的组件
  • 将这些组件组合嵌套在一起,最终形成我们的应用程序

在真实开发中,我们可以将项目进行拆分。

上面的嵌套逻辑如下,它们存在如下关系:
  • App组件是Header、Main、Footer组件的父组件
  • Main组件是Banner、ProductList组件的父组件
在开发过程中,我们会经常遇到需要 组件之间相互进行通信
  • 比如App可能使用了多个Header,每个地方的Header展示的内容不同,那么我们就需要使用者传递给Header一些数据,让其进行展示;
  • 又比如我们在Main中一次性请求了Banner数据和ProductList数据,那么就需要传递给它们来进行展示;
  • 也可能是子组件中发生了事件,需要由父组件来完成某些操作,那就需要子组件向父组件传递事件

父子组件之间传递是很重要的一个通信方式。

那么父子组件之间如何进行通信呢?

  • 父组件传递给子组件:通过props属性
  • 子组件传递给父组件:通过$emit触发事件

8.1.父组件传递给子组件

 在开发中很常见的就是父子组件之间通信,比如父组件有一些数据,需要子组件来进行展示:这个时候我们可以通过props来完成组件之间的通信

什么是Props呢?
  • Props是你可以在组件上注册一些自定义的attribute
  • 父组件给这些attribute赋值子组件通过attribute的名称获取到对应的值
<!-- App.vue -->
<template>
  <cpn name="zzz" height="1.7" age="18"></cpn> 
</template>

<script>
import cpn from './components/cpn.vue'
 export default {
  data() {
    return {
      
    }
  },
  components: {
    cpn:cpn
  }
}
</script>

<style scoped>

</style>
  1. 在App.vue父组件文件中,conponents对象定义了一个组件cpn
  2. 用import引入组件cpn文件的位置,在template里面使用cpn标签
  3. 在cpn标签中填要传入子组件的属性与值,在子组件cpn.vue接收。
<!-- cpn.vue -->
<template>
  <div class="infos">
    <h2>姓名:{
  {name}}</h2>
    <h2>年龄:{
  {age}}</h2>
    <h2>身高:{
  {height}}</h2>
  </div>
</template>

<script>
 export default {
  props:["name", "age", "height"]
}
</script>

<style scoped>

</style>
  1. 使用props属性接收传入的attribute属性名称
  2. 在template中使用传入的值,如果使用的值发现没有在props属性定义,就会去data找。

 Props有两种常见的用法:

  1. 方式一:字符串数组,数组中的字符串就是attribute的名称;
  2. 方式二:对象类型,对象类型我们可以在指定attribute名称的同时,指定它需要传递的类型、是否是必须的、默认值等等;

上面演示使用的是方式一,下面对两种用法进行说明。

8.1.1.props的数组用法

子组件的props接收父组件传递来的attribute,需要一一对应,props中保存字符串数组。

这种数组用法只能说明传入的attribute的名称不能对其进行任何形式的限制,所以在实际开发中用得更多的是props的对象用法。

8.1.2.props的对象用法

当使用对象语法的时候,我们可以对传入的内容限制更多:

  •  指定传入的attribute的类型
  • 指定传入的attribute是否是必传的
  • 指定没有传入时,attribute的默认值
props:{
    name: {
      type: String,
      required: true,
      default: "z"
    },
    age: {
      type: Number,
      required: false,
      default: 10
    },
    height: {
      type: Number,
      required: false,
      default: 1.00
    }
  }

一般attribute不是必传的时候,默认值也不写。

type的类型

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

对象类型的其他写法

 props:{
    name: String,//基础的类型检测
    age: [String, Number],//多个可能的类型
    propO:{
      type: Object,//对象和数组的默认值必须从一个工厂函数获取
      default(){
        return { message: "message"}
      }
    }
  }

prop的大小写命名

HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符

这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名

 

8.1.3.attribute继承

非prop的attribute 

在了解attribute继承之前需要了解非prop的attribute的概念。

  • 当我们传递给一个组件某个属性,但是该属性并没有定义对应的props或者emits时,就称之为 非Prop的Attribute
  • 常见的包括class、style、id属性等;

Attribute继承

组件有单个根节点 时, 非Prop的attribute将自动添加到根节点的attribute 中。
简单来说,如果父组件传递了类似于class、style、id的属性给子组件,如果子组件有单个根节点,attribute就会添加到这个根节点上。
下面的案例时父组件App.vue传递了class和id给子组件cpn.vue,看一下浏览器中子组件的class和id的根节点。 
<!-- 父组件传递了class和id App.vue -->
<template>
  <cpn class="cpn" id="cpn1" name="zzz" height="1.7" age="18"></cpn> 
</template>

<script>
import cpn from './components/cpn.vue'
 export default {
  data() {
    return {
      
    }
  },
  components: {
    cpn:cpn
  }
}
</script>

<style scoped>

</style>
<!-- cpn.vue -->
<template>
  <div class="infos">
    <h2>姓名:{
  {name}}</h2>
    <h2>年龄:{
  {age}}</h2>
    <h2>身高:{
  {height}}</h2>
  </div>
</template>

<script>
 export default {
  props:{
    name: String,
    age: [String, Number],
    propO:{
      type: Object,
      default(){
        return { message: "message"}
      }
    }
  }
}
</script>

<style scoped>

</style>

可以看到子组件的根节点继承了父组件传过来的非prop的attribute

禁用attribute继承

如果我们 不希望组件的根元素继承attribute ,可以在组件中设置 inheritAttrs: false;
//cpn.vuecpn.vue
 export default {
  inheritAttrs:false,
}
  • 禁用attribute继承的常见情况需要将attribute应用于根元素之外的其他元素
  • 我们可以通过 $attrs来访问所有的 非props的attribute
<template>
  <div class="infos">
    <h2 :class="$attrs.class">姓名:{
  {name}}</h2>
    <h2>年龄:{
  {age}}</h2>
    <h2>身高:{
  {height}}</h2>
  </div>
</template>

多个根节点的attribute

多个根节点的attribute如果没有显示的绑定,那么会报警告,我们必须手动的指定要绑定到哪一个属性上。

8.2.子组件传递给父组件

有父组件传递给子组件的情况,也有子组件传递给父组件的情况,

  • 比如子组件有一些事件发生的时候,比如在组件中发生了点击,父组件需要切换内容
  • 子组件有一些内容想要传递给父组件的时候;

现编写一个案例:父组件显示计数器的数,子组件负责增加数量按钮。

<!-- cpn.vue 子组件-->
<template>
  <div>
    <!-- 1.子组件触发事件 -->
    <button @click="addCount(1)">+1</button>
    <button @click="addCount(5)">+5</button>
    <button @click="addCount(10)">+10</button>
  </div>
</template>

<script>
 export default {
   methods: {
    // 2.子组件将自定义的事件名add和参数count通过this.$emit()传递出去
     addCount(count) {
       this.$emit("add", count)
     }
   }
 }
</script>

<style scoped>

</style>

        1.子组件触发事件;

        2. 子组件将自定义的事件名add和参数count通过this.$emit()传递出去;

<!-- App.vue 父组件 -->
<template>
  <div>
    <div class="count">当前计数{
  {counter}}</div>
    <!-- 3.父组件使用自定义的add事件,并且编写方法 -->
    <cpn @add="addClick"></cpn> 
  </div>
</template>

<script>
import cpn from './components/cpn.vue'
 export default {
  data() {
    return {
      counter: 0
    }
  },
  components: {
    cpn:cpn
  },
  methods: {
    // 4.父组件对自定义事件触发的方法进行处理
    addClick(count) {
      this.counter += count
    }
  },
}
</script>

<style scoped>

</style>

        3.父组件使用自定义的add事件,并且编写方法; 

        4.父组件对自定义事件触发的方法进行处理。 

8.2.1.emit属性

子组件中可以在属性中先注册传递出去的事件名。父组件在使用自定义事件的时候就会有提示了。

export default {
   emits:["add"],
   methods: {
    // 2.子组件将自定义的事件名add和参数count通过this.$emit()传递出去
     addCount(count) {
       this.$emit("add", count)
     }
   }
 }

9.Vue组件化 -  插槽Slot

在开发中,我们会经常封装一个个可复用的组件:
  • 前面我们会通过props传递给组件一些数据,让组件来进行展示;
  • 但是为了让这个组件具备更强的通用性,我们不能将组件中的内容限制为固定的div、span等等这些元素;
  • 比如某种情况下我们使用组件,希望组件显示的是一个按钮,某种情况下我们使用组件希望显示的是一张图片
  • 我们应该让使用者可以决定某一块区域到底存放什么内容和元素

举个例子:假如我们定制一个通用的导航组件 - NavBar
  • 1这个组件分成三块区域:左边-中间-右边,每块区域的内容是不固定;
  • 左边区域可能显示一个菜单图标,也可能显示一个返回按钮,可能什么都不显示;
  • 中间区域可能显示一个搜索框,也可能是一个列表,也可能是一个标题,等等;
  • 右边可能是一个文字,也可能是一个图标,也可能什么都不显示;

这个时候我们就可以来定义插槽slot:

  • 插槽的使用过程其实是抽取共性、预留不同
  • 我们会将共同的元素、内容依然在组件内进行封装;
  • 同时会将不同的元素使用slot作为占位,让外部决定到底显示什么样的元素;

9.1.slot的基本使用 

如何使用slot呢?

  • Vue中将 <slot> 元素作为承载分发内容的出口;
  • 在封装组件中,使用特殊的元素<slot>就可以为封装组件开启一个插槽
  • 该插槽插入什么内容取决于父组件如何使用;

有点难理解,举个例子就清晰一些了。

App.vue是父组件,slotContent.vue是子组件,slotContent里面放了slot,在App的子组件标签里面添加一些元素默认就添加到了子组件的slot里面。

9.2.slot的默认内容

如果父组件在调用子组件的时候没有往插槽里面添加内容,就会使用子组件slot的默认值。

9.3.多个插槽的效果

如果我们想要做一个顶部菜单栏,就需要把插槽分成三个部分,左部、中部、右部。如果按照上面的写法会有什么样的效果。

 会将App.vue的三个元素依次对应到slotContent.vue的slot里面吗?

并不会对应,而是相同的内容展示三次。那要怎么才能对应呢,需要使用具名插槽来实现了。

9.4.具名插槽的使用

事实上,我们希望达到的效果是插槽对应的显示,这个时候我们就可以使用 具名插槽:
  • 具名插槽顾名思义就是给插槽起一个名字,<slot> 元素有一个特殊的 attribute:name
  • 一个不带 name 的slot,会带有隐含的名字 default
<!-- App.vue-->
<template>
  <div>
    <slot-content title="标题">
      <template v-slot:left>
        <button >left</button>
      </template>
      <template v-slot:center>        
        <h2>center<
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

至尊绝伦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值