• Vue的学习 —— <vue组件>


    目录

    前言

    正文

    一、选项式API与组合式API

    二、生命周期函数

     1、onBeforeMount()

    2、onMounted()

    3、onBeforeUpdate()

    4、onUpdated()

    5、onBeforeUnmount()

    6、onUnmounted()

    三、组件之间的样式冲突

    四、父组件向子组件传递数据

    1、定义props

    2、静态绑定props

    3、动态绑定props

    4、校验props

    ① 基本类型检查

    ② 必填项的校验

    ③ 属性默认值

    ④ 自定义验证函数

    5、子组件向父组件传递数据

    ① 子组件向父组件传递自定义事件

    ② 在子组件中触发自定义事件

    ③ 在父组件中监听自定义事件


    前言

    在学习完第三章的基础知识后,已经可以编写一些简单的组件了,但是这样的组件功能比较简单,无法满足实际项目开发中各种复杂的需求。为了能够更灵活地使用组件,还需要更深入地学习组件的相关知识。

    正文

    一、选项式API与组合式API

    Vue 3支持选项式API和组合式API。其中,选项式API是从Vue 2开始使用的一种写法,而Vue 3新增了组合式API的写法。选项式API是一种通过包含多个选项的对象来描述组件逻辑的API,其常用的选项包括data、methods、computed、watch等。组合式API相比于选项式API,组合式API是将组件中的数据、方法、计算属性、侦听器等代码全部组合在一起,写在setup()函数中。

    选项式API写法如下:

    1. <script>
    2. export default {
    3.  data() {
    4.    return { // 定义数据 }
    5. },
    6.  methods: { // 定义方法 },
    7.  computed: { // 定义计算属性 },
    8.  watch: { // 定义侦听器 }
    9. }
    10. </script>

    组合式API写法如下:

    1. <script>
    2. import { computed, watch } from 'vue'
    3. export default {
    4.  setup() {
    5.    const 数据名 = 数据值
    6.    const 方法名 = () => {}
    7.    const 计算属性名 = computed(() => {})
    8.    watch(侦听器的来源, 回调函数, 可选参数)
    9.    return { 数据名, 方法名, 计算属性名 }
    10. }
    11. }
    12. script>

    Vue提供的选项式API和组合式API这两种写法可以覆盖大部分的应用场景,它们是同一底层系统所提供的两套不同的接口。选项式API是在组合式API的基础上实现的。

    二、生命周期函数

    每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM。在此过程中,它也会运行被称为生命周期钩子的函数,让开发者有机会在特定阶段运行自己的代码。

    Vue生命周期如下图所示:

    • 以下将在 vite 创建的工程中,举例说明生命周期函数

    • beforecatecreated,它们已经被setup方法本身所取代

    • 以下钩子都应该在组件的 setup() 阶段被同步调用

     1、onBeforeMount()

    作用在组件被挂载之前被调用。(获取不到 DOM 元素)

    描述:当这个钩子被调用时,组件已经完成了其响应式状态的设置,但还没有创建 DOM 节点。它即将首次执行 DOM 渲染过程。

    2、onMounted()

    作用在组件挂载完成后执行。(可以获取到DOM 元素)

    描述:组件在以下情况下被视为已挂载:

    • 其所有同步子组件都已经被挂载 (不包含异步组件或 树内的组件)。

    • 其自身的 DOM 树已经创建完成并插入了父容器中。注意仅当根容器在文档中时,才可以保证组件 DOM 树也在文档中。

    这个钩子通常用于执行需要访问组件所渲染的 DOM 树相关的副作用,或是在服务端渲染应用中用于确保 DOM 相关代码仅在客户端执行。一般在这里进行数据网络请求操作

    下面演示onMounted()函数的用法:

    1. 创建src\components\onMountedDemo.vue文件用于存放演示代码,写入如下代码:

      1. <script setup>
      2. import { onBeforeMount, onMounted } from "vue";
      3. console.log('setup')
      4. onBeforeMount(() => {
      5.  console.log('onBeforeMount —— 组件挂载前执行')
      6. })
      7. onMounted(() => {
      8.  console.log('onMounted —— 组件挂载后执行')
      9. })
      10. script>
    2. 修改src\main.js文件,切换页面中显示的组件

      import App from './components/onMountedDemo.vue'
    3. 保存代码,使用浏览器访问http://127.0.0.1:5173/,打开开发者控制台,页面效果如下图所示:

    3、onBeforeUpdate()

    作用在组件即将因为响应式状态变更而更新其 DOM 树之前调用。

    描述:这个钩子可以用来在 Vue 更新 DOM 之前访问 DOM 状态。在这个钩子中更改状态也是安全的。

    4、onUpdated()

    作用在组件因为响应式状态变更而更新其 DOM 树之后调用。

    描述

    • 父组件的更新钩子将在其子组件的更新钩子之后调用。

    • 这个钩子会在组件的任意 DOM 更新后被调用,这些更新可能是由不同的状态变更导致的。如果你需要在某个特定的状态更改后访问更新后的 DOM,请使用 nextTick() 作为替代。

    下面演示以上钩子的使用方法:

    1. 创建src\components\onMountedDemo.vue文件用于存放演示代码,写入如下代码:

      1. <template>
      2.  <div>
      3.    <h2>count 计数为:{{count}}</h2>
      4.    <button @click="count++">点击 + 1</button>
      5.  </div>
      6. </template>
      7. <script setup>
      8. import { onBeforeMount, onBeforeUpdate, onMounted, onUpdated, ref } from "vue";
      9. const count = ref(0)
      10. console.log('setup')
      11. // 1
      12. onBeforeMount(() => {
      13.  console.log('onBeforeMount —— 组件挂载前执行')
      14. })
      15. // 2
      16. onMounted(() => {
      17.  console.log('onMounted —— 组件挂载后执行')
      18.  console.log('===============================================')
      19. })
      20. // 3
      21. onBeforeUpdate(() => {
      22.  console.log('onBeforeUpdate —— 数据更新前调用')
      23. })
      24. // 4
      25. onUpdated(() => {
      26.  console.log('onUpdated —— 数据更新后调用')
      27. })
      28. </script>
    2. 修改src\main.js文件,切换页面中显示的组件

      import App from './components/onUpdated.vue'
    3. 保存代码,使用浏览器访问http://127.0.0.1:5173/,打开开发者控制台,点击页面上的“点击 + 1” 按钮,页面效果如下图所示:

    5、onBeforeUnmount()

    作用组件内实例被卸载之前调用

    描述:当这个钩子被调用时,组件实例依然还保有全部的功能。

    6、onUnmounted()

    作用在组件实例被卸载之后调用

    描述:一个组件在以下情况下被视为已卸载:

    • 其所有子组件都已经被卸载。

    • 所有相关的响应式作用 (渲染作用以及 setup() 时创建的计算属性和侦听器) 都已经停止。

    可以在这个钩子中手动清理一些副作用,例如计时器、DOM 事件监听器或者与服务器的连接。

    以上钩子代码示例:

    App.vue组件中,通过 v-if 指令,控制 Hello.vue 组件的显示隐藏,来模拟组件的挂载/卸载,

    下面演示卸载生命周期的用法:

    1. 创建src\components\unInstall.vue文件用于存放演示代码,写入如下代码:

      1. <template>
      2.    <div>
      3.      <h2>uninstall 组件</h2>
      4.    </div>
      5.  </template>
      6.  
      7.  <script setup>
      8.  import { onBeforeUnmount, onUnmounted } from "vue";
      9.  onBeforeUnmount(() => {
      10.    console.log('onBeforeUnmount —— 组件卸载前执行')
      11. })
      12.  onUnmounted(() => {
      13.    console.log('onUnmounted —— 组件卸载后执行')
      14. })
      15.  
      16.  </script>
    2. 在src/components/App.vue文件中显示上面创建的unInstall.vue组件,代码如下:

      1. <template>
      2.  <div>
      3.    <h2>count 计数为:{{count}}</h2>
      4.    <button @click="count++">点击 + 1</button>
      5.    <hr>
      6.    <unInstall v-if="display"/>
      7.    <button @click="display=!display">挂载/卸载unInstall组件</button>
      8.  </div>
      9. </template>
      10. <script setup>
      11. import { onBeforeMount, onBeforeUpdate, onMounted, onUpdated, ref } from "vue";
      12. import unInstall from './components/unInstall.vue'
      13. const count = ref(0)
      14. const display = ref(true)
      15. console.log('setup')
      16. // 1
      17. onBeforeMount(() => {
      18.  console.log('onBeforeMount —— 组件挂载前执行')
      19. })
      20. // 2
      21. onMounted(() => {
      22.  console.log('onMounted —— 组件挂载后执行')
      23.  console.log('===============================================')
      24. })
      25. // 3
      26. onBeforeUpdate(() => {
      27.  console.log('onBeforeUpdate —— 数据更新前调用')
      28. })
      29. // 4
      30. onUpdated(() => {
      31.  console.log('onUpdated —— 数据更新后调用')
      32.  console.log('===============================================')
      33. })
      34. </script>
    3. 修改src\main.js文件,切换页面中显示的组件

      import App from './App.vue'
    4. 保存代码,使用浏览器访问http://127.0.0.1:5173/,打开开发者控制台,点击页面上的“挂载/卸载unInstall组件” 按钮,页面效果如下图所示:

    三、组件之间的样式冲突

    在默认情况下,写在Vue组件中的样式会全局生效,很容易造成多个组件之间的样式冲突问题。例如,为Component1组件中的h5元素添加边框样式,其他组件则不添加,同时显示在页面上。具体代码如下:

    1. <!-- Component1 -->
    2. <template>
    3.    <h5>组件1</h5>
    4. </template>
    5. <style>
    6. h5 {
    7.    border: 1px dotted black;
    8. }
    9. </style>
    10. <!-- Component2 -->
    11. <template>
    12.    <h5>组件2</h5>
    13. </template>
    14. <!-- Component3 -->
    15. <template>
    16.    <h5>组件3</h5>
    17. </template>
    18. <!-- App.vue -->
    19. <template>
    20.  <div>
    21.    <Componet1/>
    22.    <Componet2/>
    23.    <Componet3/>
    24.  </div>
    25. </template>
    26. <script setup>
    27. import Componet1 from './components/Componet1.vue';
    28. import Componet2 from './components/Componet2.vue';
    29. import Componet3 from './components/Componet3.vue';
    30. </script>

    在main.js切换App.vue显示,保存代码后,使用浏览器访问http://localhost:5173/,页面效果如下:

    image-20240123102739135

    从上图可以看出,Component1组件、Component2组件和Component3组件中h5元素的边框样式都发生了改变,但是代码中只有Component1组件设置了边框样式效果,说明组件之间存在样式冲突。

    导致组件之间会产生样式冲突的原因:

    导致组件之间样式冲突的根本原因是:在单页Web应用中,所有组件的DOM结构都是基于唯一的index.html页面进行呈现的。每个组件中的样式都可以影响整个页面中的DOM元素。在Vue中可以使用scoped属性和深度选择器来解决组件之间的样式冲突。Vue为