Vue3 中组件的使用(上)

2024-03-07 1734阅读

温馨提示:这篇文章已超过387天没有更新,请注意相关的内容是否还可用!

目录

  • 前言:
  • 一、什么是组件
  • 二、注册组件
    • 1. 全局注册
    • 2. 局部注册
    • 二、传递数据【父 -> 子】
      • 1. 字符串数组的形式
      • 2. 对象的形式
      • 三、组件事件【子 -> 父】
        • 1. 字符串数组式声明自定义事件
        • 2. 【子组件】触发组件事件
        • 3. 【父组件】监听子组件自定义事件
        • 4. 组件事件例子
        • 总结:

          前言:

          在编写vue里的SPA(Single Page Application单页面应用)时,我们始终绕不开组件的使用,Vue3 里有一些重要更新,在这里分享给大家。


          一、什么是组件

          组件(Component)是 Vue.js 最强大的功能之一。

          组件可以扩展 HTML 元素,封装可重用的代码。

          组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树:

          Vue3 中组件的使用(上)

          组件就相当于页面的零件,当做正常的标签使用,不过能够进行自定义的数据传输和事件监听。

          组件内也能使用其他的组件,任意处都能够使用。


          二、注册组件

          一个 Vue 组件在使用前需要先被 “注册”,这样 Vue 才能在渲染模板时找到其对应的实现;组件注册有两种方式:全局注册、局部注册


          1. 全局注册

          可使用 app.component(name, Component)注册组件的方法,在此应用的任意组件的模板中使用

          • name:注册的名字
          • Component:需要注册的组件
            // 在 main.js 中注册全局组件
            import { createApp } from 'vue'
            import App from './App.vue'
            // 1:引入需要被注册的组件
            import Login from './components/Login.vue' 
            const app = createApp(App)
            // 2:全局注册组件
            app.component('MLogin', Login)
            app.mount('#app')
            
            // 我们使用注册的组件
            
                

            登录系统


            2. 局部注册

            局部注册的组件需要在使用它的父组件中显式导入,并且只能在该父组件中使用

            在组合式 API 中的 内,直接导入的组件就可以在模板中直接可用,无需注册。

            // 1:引入需要注册的组件,无需注册
            import LoginVue from './components/Login.vue';
            
            
                

            登录系统


            二、传递数据【父 -> 子】

            如果父组件向子组件进行传递数据,那么我们需要在子组件中声明 props 来接收传递数据的属性,可采用字符串数组式或对象式来声明 props

            父组件向子组件传递数据,在使用组件

            let 的标签上采用属性方式传递的 props 值,可使用 v-bind: 或 : 来绑定属性

            组件中 props 中的数据是只读的,不可直接更改,只能通过父组件进行更改

            声明与使用

            1. 在选项式 API 中

              1. 我们可以提供 props 选项来声明接收传递的数据

              2. 在 JS 中可使用 this.$props 来访问声明的自定义的属性

              3. 在视图模板中,可直接访问 props 中声明的自定义属性

            2. 在组合式 API 中

              1. 我们可以采用 defineProps 宏来声明接收传递的数据

              2. 在 JS 中可使用 defineProps 返回的对象来访问声明的自定义的属性

              3. 在视图模板中,可直接访问 defineProps 中声明的自定义属性


            1. 字符串数组的形式

            // 字符串数组的形式
            
              
            // 使用 defineProps 宏来声明
            defineProps(['flat', 'title']) 
              
            
            

            例子:

            // 父组件
            
            import { ref } from 'vue';
            import ButtonVue from './components/Button.vue';
            let isError = ref(false) // 主题
            let isFlat = ref(false) // 阴影
            let btnText = ref('普通按钮') // 按钮文本
            
            
                主题:
                阴影:
                按钮文本:
                
            // 子组件
            
            // 声明接收父组件传递的属性值:自定义属性
            let propsData = defineProps(['title', 'error', 'flat'])
            function showPropsData() {
                // 在 JS 中,需要通过 defineProps 返回对象来访问 props 的内容
                console.log(propsData)
                console.log(propsData.title)
                console.log(propsData.error)
                console.log(propsData.flat)
            }
            function changeErrorProps() {
                // 不能直接修改 props 的数据,因为是只读的
                propsData.error = !propsData.error
            }
            
            
                
                
                    {{ title }}
                
            
            
            button {
                border: none;
                padding: 12px 25px;
            }
            .error {
                background-color: rgb(197, 75, 75);
                color: white;
            }
            .flat {
                box-shadow: 0 0 10px grey;
            }
            
            

            2. 对象的形式

            对象形式声明的 props,可以对传来的值进行校验,如果传入的值不满足类型要求,会在浏览器控制台中抛出警告来提醒使用者

            对象形式声明的 props,key 是 prop 的名称,值则为约束的条件

            对象中的属性:

            type:类型,如 String、Number、Boolean、Array、Object、Date、Function、Symbol

            default:默认值;对象或者数组应当用工厂函数返回

            required:是否必填,布尔值

            validator:自定义校验,函数类型

            // 对象的形式
                defineProps({
                    // 基础类型检查
                    // (给出 `null` 和 `undefined` 值则会跳过任何类型检查)
                    propA: Number,
                    // 多种可能的类型
                    propB: [String, Number],
                    // 必传,且为 String 类型
                    propC: {
                        type: String,
                        required: true
                    },
                    // Number 类型的默认值
                    propD: {
                        type: Number,
                        default: 100
                    },
                    // 对象类型的默认值
                    propE: {
                        type: Object,
                        // 对象或数组的默认值
                        // 必须从一个工厂函数返回。
                        // 该函数接收组件所接收到的原始 prop 作为参数。
                        default(rawProps) {
                            return { message: 'hello' }
                        }
                    },
                    // 自定义类型校验函数
                    propF: {
                        validator(value) {
                            // The value must match one of these strings
                            return ['success', 'warning', 'danger'].includes(value)
                        }
                    },
                    // 函数类型的默认值
                    propG: {
                        type: Function,
                        // 不像对象或数组的默认,这不是一个工厂函数。这会是一个用来作为默认值的函数
                        default() {
                            return 'Default function'
                        }
                    }
                })
            
            

            例子:

            // 父组件
            
            import { ref } from 'vue';
            import ButtonVue from './components/Button.vue';
            let isError = ref(false) // 主题
            let isFlat = ref(false) // 阴影
            let btnText = ref('普通按钮') // 按钮文本
            
            
                主题:
                阴影:
                按钮文本:
                
            // 子组件
            
            // 声明接收父组件传递的属性值:自定义属性
            let propsData = defineProps({
                title: {
                    type: String,
                    required: true
                },
                error: Boolean,
                flat: Boolean,
                tips: {
                    type: String,
                    default: '我是一个普通的按钮'
                }
            })
            function showPropsData() {
                // 在 JS 中,需要通过 defineProps 返回对象来访问 props 的内容
                console.log(propsData)
                console.log(propsData.title)
                console.log(propsData.error)
                console.log(propsData.flat)
            }
            function changeErrorProps() {
                // 不能直接修改 props 的数据,因为是只读的
                propsData.error = !propsData.error
            }
            
            
                
                
                    {{ title }}
                
            
            
            button {
                border: none;
                padding: 12px 25px;
            }
            .error {
                background-color: rgb(197, 75, 75);
                color: white;
            }
            .flat {
                box-shadow: 0 0 10px grey;
            }
            
            

            注意:

            1. 所有 prop 默认都是可选的,除非声明了 required: true
            2. 除 Boolean 外的未传递的可选prop将会有一个默认值 undefined
            3. Boolean 类型的未传递 prop 将被转换为 false;
            4. 当 prop 的校验失败后,Vue 会抛出一个控制台警告【在开发模式下】
            5. 注意 prop 的校验是在组件实例被创建之前

              1. 在选项式 API 中,实例的属性(比如 data、computed 等) 将在 default 或 validator 函数中不可用

              2. 在组合式 API 中,defineProps 宏中的参数不可以访问 中定义的其他变量,因为在编译时整个表达式都会被移到外部的函数中

            特别提醒:

            关于 Boolean 类型转换:

            为了更贴近原生 boolean attributes 的行为,声明为 Boolean 类型的 props 有特别的类型转换规则

            如声明时:defineProps({ error: Boolean })

            传递数据时:

            - :相当于

            - :相当于


            三、组件事件【子 -> 父】

            有的时候,父组件在使用子组件时,子组件如何给父组件传值呢?

            1. 子组件声明自定义的事件
            2. 子组件中触发自定义事件(可传值)
            3. 父组件使用子组件时监听对应的自定义事件,并执行父组件中的函数(获取子组件传递的值)

            1. 字符串数组式声明自定义事件

            1. 在选项式 API 中,子组件可通过 emits 选项来声明自定义的事件
            2. 在组合式 API 中,子组件可通过 defineEmits() 宏来声明自定义的事件

            字符串数组式声明自定义事件

            采用字符串数组可以声明简单的自定义事件:

                defineEmits(['inFocus', 'submit'])
            
            

            对象式声明自定义事件

            采用对象式声明自定义事件,还可以进行校验传递的参数是否符合预期要求

            对象式声明自定义事件中,属性名为自定义事件名,属性值则是是否验证传递的参数:

            1. 属性值为 null 则不需要验证
            2. 属性值为函数时,参数为传递的数据,函数返回 true 则验证通过,返回 false 则验证失败,验证失败可以用警告语句提示开发者【注意:无论是 true 还是 false 都会继续执行下去的,父组件都会获取到传递的值】
             
            defineEmits({
                autoEvent1: null, // 无需校验
                // 需要校验,param 可以是多个参数,返回布尔值来表明事件是否合法
                autoEvent2: (param) => {
                    // true 则通过
                    // false 则不通过,可以在控制台输入警告语句
                }
            })
            
            

            2. 【子组件】触发组件事件

            在选项式 API 中,可通过组件当前实例 this.$emit(event, ...args) 来触发当前组件自定义的事件

            在组合式 API 中,可调用 defineEmits 宏返回的 emit(event, ...args) 函数来触发当前组件自定义的事件

            其中上方两个参数分别为:

            • event:触发事件名,字符串类型
            • ...args:传递参数,可没有,可多个
              // 自定义事件,并返回 emit 函数
              const emit = defineEmits(['changeAge'])
              function emitAgeEvent() {
                  // 触发自定义事件 changeAge,并传递参数 1,20
                  emit('changeAge', 1, 20)
              }
              
              
                  触发自定义事件
                  
              触发自定义事件

              3. 【父组件】监听子组件自定义事件

              使用 v-on:event="callback" 或者 @event="callback" 来监听子组件是否触发了该事件

              1. event:事件名字(camelCase 形式命名的事件,在父组件中可以使用 kebab-case 形式来监听)
              2. callback:回调函数,如果子组件触发该事件,那么在父组件中执行对应的回调函数,回调函数声明参数可自动接收到触发事件传来的值
              import { ref } from 'vue';
              import ButtonVue from './components/Button.vue';
              let startAge = ref(0)
              let endAge = ref(0)
              // 子组件触发事件的回调函数
              function addAge(start_age, end_age) {
                  console.log('----------------');
                  console.log(start_age)
                  console.log(end_age)
                  startAge.value = start_age
                  endAge.value = end_age
              }
              
              
                  

              开始年龄:{{ startAge }}

              结束年龄:{{ endAge }}


              4. 组件事件例子

              字符串数组式声明自定义事件

              // 父组件
              
              import { reactive } from 'vue';
              import StudentVue from './components/Student.vue';
              let student = reactive({
                  name: 'Jack',
                  age: 18,
                  sex: '男'
              })
              // 获取子组件传递值
              function getNewAge(newAge) {
                  console.log('年龄的新值:' + newAge)
                  student.age = newAge
              }
              function getNewAgeAndName(newAge, newName) {
                  console.log('年龄的新值:' + newAge)
                  console.log('名字的新值:' + newName)
                  student.age = newAge
                  student.name = newName
              }
              function getNewStudent(stu){
                  console.log('学生新值:');
                  console.log(stu);
                  student.age = stu.age
                  student.name = stu.name
                  student.sex = stu.sex
              }
              
              
                  {{ student }}
                  
              // 子组件
              
              // 自定义事件
              let emit = defineEmits(['changeAge', 'changeAgeAndName', 'changeStudent'])
              function emitEventAge() {
                  // 选项式通过 this.$emit 触发自定义事件,并传值
                  emit('changeAge', 30)
              }
              
              
                  更改年龄
                  

              更改年龄和名字

              更改学生(验证通过)

              更改学生(验证失败)

              对象式声明自定义事件

              // 父组件
              
              import { reactive } from 'vue';
              import StudentVue from './components/Student.vue';
              let student = reactive({
                  name: 'Jack',
                  age: 18,
                  sex: '男'
              })
              // 获取子组件传递值
              function getNewAge(newAge) {
                  console.log('年龄的新值:' + newAge)
                  student.age = newAge
              }
              function getNewAgeAndName(newAge, newName) {
                  console.log('年龄的新值:' + newAge)
                  console.log('名字的新值:' + newName)
                  student.age = newAge
                  student.name = newName
              }
              function getNewStudent(stu){
                  console.log('学生新值:');
                  console.log(stu);
                  student.age = stu.age
                  student.name = stu.name
                  student.sex = stu.sex
              }
              
              
                  {{ student }}
                  
              // 子组件
              
              // 自定义事件
              let emit = defineEmits({
                  changeAge: null, // 无需验证
                  changeAgeAndName: null, // 无需验证
                  changeStudent: stu => {
                      if (stu.age 
                          console.warn('年龄不得小于等于0')
                          // false:验证不通过,会有警告语句,父组件依旧可以获取该值
                          return false
                      }
                      // true:验证通过
                      return true
                  }
              })
              function emitEventAge() {
                  // 选项式通过 this.$emit 触发自定义事件,并传值
                  emit('changeAge', 30)
              }
              
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]