Vue3 中组件的使用(上)

这篇具有很好参考价值的文章主要介绍了Vue3 中组件的使用(上)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:

在编写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')
// 我们使用注册的组件
<template>
    <h3>登录系统</h3>
    <!-- 使用全局注册的组件 -->
    <MLogin />
</template>

2. 局部注册

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

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

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

<template>
    <h3>登录系统</h3>
    <!-- 2:使用全局注册的组件 -->
    <LoginVue />
</template>

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

如果父组件向子组件进行传递数据,那么我们需要在子组件中声明 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. 字符串数组的形式

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

例子:

// 父组件
<script setup>
import { ref } from 'vue';
import ButtonVue from './components/Button.vue';

let isError = ref(false) // 主题
let isFlat = ref(false) // 阴影
let btnText = ref('普通按钮') // 按钮文本
</script>

<template>
    主题:<input type="checkbox" v-model="isError">
    阴影:<input type="checkbox" v-model="isFlat">
    按钮文本:<input type="text" v-model="btnText">
    <hr>
    <!-- 父向子传值,可采用属性的方式赋值 -->
    <ButtonVue :title="btnText" :error="isError" :flat="isFlat"/>
</template>
// 子组件
<script setup>
// 声明接收父组件传递的属性值:自定义属性
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
}
</script>


<template>
    <!-- 在视图模板上,可直接使用 props 中的属性 -->
    <button :class="{ error, flat }" @click="showPropsData" @mousedown.right="changeErrorProps">
        {{ title }}
    </button>
</template>


<style>
button {
    border: none;
    padding: 12px 25px;
}

.error {
    background-color: rgb(197, 75, 75);
    color: white;
}

.flat {
    box-shadow: 0 0 10px grey;
}
</style>

2. 对象的形式

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

对象中的属性:

type:类型,如 StringNumberBooleanArrayObjectDateFunctionSymbol
default:默认值;对象或者数组应当用工厂函数返回
required:是否必填,布尔值
validator:自定义校验,函数类型

<script>
// 对象的形式
    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'
            }
        }
    })
</script>

例子:

// 父组件
<script setup>
import { ref } from 'vue';
import ButtonVue from './components/Button.vue';

let isError = ref(false) // 主题
let isFlat = ref(false) // 阴影
let btnText = ref('普通按钮') // 按钮文本
</script>

<template>
    主题:<input type="checkbox" v-model="isError">
    阴影:<input type="checkbox" v-model="isFlat">
    按钮文本:<input type="text" v-model="btnText">
    <hr>
    <!-- 父向子传值,可采用属性的方式赋值 -->
    <ButtonVue :title="btnText" :error="isError" :flat="isFlat"/>
</template>
// 子组件
<script setup>
// 声明接收父组件传递的属性值:自定义属性
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
}
</script>


<template>
    <!-- 在视图模板上,可直接使用 props 中的属性 -->
    <button :title="tips" :class="{ error, flat }" @click="showPropsData" @mousedown.right="changeErrorProps">
        {{ title }}
    </button>
</template>


<style>
button {
    border: none;
    padding: 12px 25px;
}

.error {
    background-color: rgb(197, 75, 75);
    color: white;
}

.flat {
    box-shadow: 0 0 10px grey;
}
</style>

注意:

  1. 所有 prop 默认都是可选的,除非声明了 required: true
  2. Boolean 外的未传递的可选prop将会有一个默认值 undefined
  3. Boolean 类型的未传递 prop 将被转换为 false
  4. prop 的校验失败后,Vue 会抛出一个控制台警告【在开发模式下】
  5. 注意 prop 的校验是在组件实例被创建之前
    1. 在选项式 API 中,实例的属性(比如 datacomputed 等) 将在 defaultvalidator 函数中不可用
    2. 在组合式 API 中,defineProps 宏中的参数不可以访问 <script setup> 中定义的其他变量,因为在编译时整个表达式都会被移到外部的函数中

特别提醒:

关于 Boolean 类型转换:
为了更贴近原生 boolean attributes 的行为,声明为 Boolean 类型的 props 有特别的类型转换规则
如声明时:defineProps({ error: Boolean })
传递数据时:
- <MyComponent error/>:相当于 <MyComponent :error="true" />
- <MyComponent />:相当于 <MyComponent :error="false" />


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

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

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

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

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

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

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

<script setup>
    defineEmits(['inFocus', 'submit'])
</script>

对象式声明自定义事件

采用对象式声明自定义事件,还可以进行校验传递的参数是否符合预期要求
对象式声明自定义事件中,属性名为自定义事件名,属性值则是是否验证传递的参数:

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

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

在选项式 API 中,可通过组件当前实例 this.$emit(event, ...args) 来触发当前组件自定义的事件
在组合式 API 中,可调用 defineEmits 宏返回的 emit(event, ...args) 函数来触发当前组件自定义的事件
其中上方两个参数分别为:

  • event:触发事件名,字符串类型
  • ...args:传递参数,可没有,可多个
<script setup>

// 自定义事件,并返回 emit 函数
const emit = defineEmits(['changeAge'])

function emitAgeEvent() {
    // 触发自定义事件 changeAge,并传递参数 1,20
    emit('changeAge', 1, 20)
}
</script>

<template>
    <button @click="emitAgeEvent">触发自定义事件</button>
    <hr>
    <!-- 触发自定义事件 changeAge,并传递参数 30 -->
    <button @click="emit('changeAge', 30)">触发自定义事件</button>
</template>

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

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

  1. event:事件名字(camelCase 形式命名的事件,在父组件中可以使用 kebab-case 形式来监听)
  2. callback:回调函数,如果子组件触发该事件,那么在父组件中执行对应的回调函数,回调函数声明参数可自动接收到触发事件传来的值
<script setup>
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
}
</script>

<template>
    <h3>
        开始年龄:{{ startAge }}
    </h3>
    <h3>
        结束年龄:{{ endAge }}
    </h3>
    
    <!-- 使用引入的组件,并通过属性传递数据 -->
    <ButtonVue @change-age="addAge" />
</template>

4. 组件事件例子

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

// 父组件
<script setup>
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
}
</script>

<template>
    {{ student }}
    <hr>
    <StudentVue 
                @change-student="getNewStudent"
                @change-age-and-name="getNewAgeAndName" 
                @change-age="getNewAge" />
</template>
// 子组件
<script setup>
// 自定义事件
let emit = defineEmits(['changeAge', 'changeAgeAndName', 'changeStudent'])

function emitEventAge() {
    // 选项式通过 this.$emit 触发自定义事件,并传值
    emit('changeAge', 30)
}

</script>

<template>
    <button @click="emitEventAge">更改年龄</button>
    <br>
    <br>
    <button @click="emit('changeAgeAndName', 10, 'Annie')">
        更改年龄和名字
    </button>
    <br>
    <br>
    <button @click="emit('changeStudent', { age: 40, name: 'Drew', sex: '男' })">
        更改学生(验证通过)
    </button>
    <br>
    <br>
    <button @click="emit('changeStudent', { age: -10, name: 'Tom', sex: '男' })">
        更改学生(验证失败)
    </button>
</template>

对象式声明自定义事件

// 父组件
<script setup>
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
}
</script>

<template>
    {{ student }}
    <hr>
    <StudentVue 
                @change-student="getNewStudent"
                @change-age-and-name="getNewAgeAndName" 
                @change-age="getNewAge" />
</template>
// 子组件
<script setup>
// 自定义事件
let emit = defineEmits({
    changeAge: null, // 无需验证
    changeAgeAndName: null, // 无需验证
    changeStudent: stu => {
        if (stu.age <= 0) {
            console.warn('年龄不得小于等于0')
            // false:验证不通过,会有警告语句,父组件依旧可以获取该值
            return false
        }
        // true:验证通过
        return true
    }
})

function emitEventAge() {
    // 选项式通过 this.$emit 触发自定义事件,并传值
    emit('changeAge', 30)
}

</script>

<template>
    <button @click="emitEventAge">更改年龄</button>
    <br>
    <br>
    <button @click="emit('changeAgeAndName', 10, 'Annie')">
        更改年龄和名字
    </button>
    <br>
    <br>
    <button @click="emit('changeStudent', { age: 40, name: 'Drew', sex: '男' })">
        更改学生(验证通过)
    </button>
    <br>
    <br>
    <button @click="emit('changeStudent', { age: -10, name: 'Tom', sex: '男' })">
        更改学生(验证失败)
    </button>
</template>

总结:

欢迎大家加入我的社区,在社区中会不定时发布一些精选内容:https://bbs.csdn.net/forums/db95ba6b828b43ababd4ee5e41e8d251?category=10003


以上就是 Vue3 中组件的使用(上),不懂得也可以在评论区里问我或私聊我询问,以后会持续发布一些新的功能,敬请关注。
我的其他文章:https://blog.csdn.net/weixin_62897746?type=blog文章来源地址https://www.toymoban.com/news/detail-426823.html

到了这里,关于Vue3 中组件的使用(上)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Vue3 中组件的使用(上)

    在编写vue里的SPA(Single Page Application单页面应用)时,我们始终绕不开组件的使用,Vue3 里有一些重要更新,在这里分享给大家。 组件( Component )是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大

    2023年04月27日
    浏览(28)
  • vue3组件引用使用的坑

    今天准备用el-tabs写个页面,发现点击后组件怎么都显示不了,后来才发现是组件引用的原因  这是页面是显示的效果:  乍一看确实是对的。。。 但是当我点击完这三个tab后再重新点击道路管理后,有意思的出现了:  one组件消失不见了,不仅如此,另外两个组件也不显示

    2024年02月16日
    浏览(33)
  • vue3使用自定义组件内方法

    使用 defineExpose 来导出方法 script setup 组件时默认不导出属性方法的(类似 java 的 private ),即通过 ref 获取实例是无法访问到自定义的属性和方法,但是可以获取到组件实例。 可以通过 defineExpose 来指定要暴露的方法属性,便可以在外部访问到组件自定义的属性方法了。 当然也

    2024年01月19日
    浏览(33)
  • 毕业设计:Vue3+FastApi+Python+Neo4j实现主题知识图谱网页应用——前言

    资源链接:https://download.csdn.net/download/m0_46573428/87796553 前言:毕业设计:Vue3+FastApi+Python+Neo4j实现主题知识图谱网页应用——前言_人工智能技术小白修炼手册的博客-CSDN博客 首页与导航:毕业设计:Vue3+FastApi+Python+Neo4j实现主题知识图谱网页应用——前端:首页与导航栏_人工智

    2024年02月14日
    浏览(48)
  • Vue3中使用component :is 加载组件

    1.不使用setup语法糖,这种方式和vue2差不多,is可以是个字符串 2. 使用setup语法糖,这时候的is如果使用字符串会加载不出来,得使用组件实例 第一种方式 第二种方式

    2024年02月16日
    浏览(45)
  • 从0搭建Vue3组件库(五): 如何使用Vite打包组件库

    本篇文章将介绍如何使用 vite 打包我们的组件库,同时告诉大家如何使用插件让打包后的文件自动生成声明文件(*.d.ts) 打包配置 vite 专门提供了库模式的打包方式,配置其实非常简单,首先全局安装 vite 以及@vitejs/plugin-vue pnpm add vite @vitejs/plugin-vue -D -w 在 components 文件下新建vite.

    2024年01月24日
    浏览(53)
  • 简单使用vue拖拽组件vue3-dnd

    项目中需要使用到拖拽,这里使用vue3-dnd来满足需求 这里项目使用的vue3(使用js而非ts) 插件官网地址:Vue3 DnD 安装 然后在app.vue里面添加代码  通过DndProvider组件为项目提供拖拽功能  概念 项目item和类型:被拖拽的对象我们称呼为某种类型的项目,类型的作用是让放置目标

    2023年04月13日
    浏览(47)
  • 在Vue.js中,什么是单文件组件(Single File Component)?它的结构是怎样的?

    聚沙成塔·每天进步一点点 前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发者,这里都将为你提供一个系统而

    2024年02月07日
    浏览(50)
  • jeecgboot vue3使用DatePicker组件设置可用日期

    文档: Ant Design Vue文档 (1)使用表单的formSchema中的componentProps组件属性通过disabledDate设置 (2)使用插槽slot方式实现

    2024年02月10日
    浏览(59)
  • vue3 使用 mitt 插件实现非父子组件传值

    介绍 : mitt 是一个 JavaScript 库,用于实现事件的订阅和发布 1、安装 2、新建 utils/eventBus.ts 文件 3、使用

    2024年02月09日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包