学习vue3第十二节(组件的使用与类型)

news2024/11/24 23:10:12

1、组件的作用用途

目的:
提高代码的复用度,和便于维护,通过封装将复杂的功能代码拆分为更小的模块,方便管理,
当我们需要实现相同的功能时,我们只需要复用已经封装好的组件,而不需要重新编写相同的代码

好处:
代码复用:我们可以在多个地方复用封装好的组件,而不需要在每个地方都写相同的代码。
易于维护:当我们需要修改某个功能时,我们只需要在一个地方修改即可,而不需要在多个地方修改。
易于理解:通过将复杂的功能分解为更小的部分,我们可以更容易地理解和管理代码
单一职责:组件应该只做一件事情,而不是承担多个无关的职责,避免过度封装,导致功能复杂化

2、组件的分类

2.1. 全局组件

好处:只需要在main.ts 中挂载注册,不用在使用页面中一个一个的引入注册,减少了代码的冗杂;
坏处:会导致组件之间的依赖关系不明确,导致组件之间查找调试错误时候难以追踪具体位置;
同时,由于全局组件会被打包的打包后的文件中,导致初始化首屏加载时间长,编译和预处理时间长,从而影响用户的体验;谨慎使用全局组件

首先我们会先将一个vue组件定义在一个单独的.vue文件中,这就是单文件组件
如:定义一个全局的顶部搜索栏 headerForm.vue 文件

// headerForm.vue
<template>
  <div class="header-form">
    全局顶部搜索栏
    name:{{ defineProps.name }}
    <el-row>
      <el-col :span="6">
        <el-form :inline="true" :model="formInline" class="demo-form-inline">
          <el-form-item label="用户名">
            <el-input v-model="formInline.user" placeholder="请输入用户名"></el-input>
          </el-form-item>
        </el-form>
      </el-col>
    </el-row>
  </div>
</template>
<script setup>
import { ref, watch, onMounted } from 'vue'
// defineProps 是vue3中新增的宏,用于处理接收 props 的属性,不需要引入,可以直接在setup 语法糖中使用;后续文章会专门介绍
const defineProps = defineProps({
  name: {
    type: String,
    default: ''
  }
})
// 此处使用了 ref() 函数 创建了 对象,为什么不用reactive() 函数呢?因为使用reactive() 函数,要使用嵌套函数保持响应式 需要使用 toRefs() 将其转换ObjectRefImpl 对象,详情请看 第五节
let formInline = ref({
  user: defineProps.name // 将user默认值设置为父组件传入的name 属性值
})
// watch 的相关内容请看第六节 watch
watch(() => defineProps.name, (n,o) => {
  // 监听name 的变化,用于同步更新user属性;
  formInline.value.user = defineProps.name
})
</script>
<style lang='scss' scoped>
.header-form{
  width: 100vw;
  height: 46px;
}
</style>
// main.ts
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import App from './App.vue'
<!-- 引入全局组件 -->
import HeaderFrom from './components/headerForm.vue'
import 'element-plus/dist/index.css'
import './style.css'
const app = createApp(App)
<!-- 挂载全局组件 -->
// app.component('注册的组件名称', 引入的单文件组件)
app.component('HeaderFrom', HeaderFrom) // 支持链式调用

<!-- 如果全局组件比较多,可以这样使用,将element的所有图标注册到项目中,非必要勿用 -->
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component)
}

app.use(ElementPlus)
app.mount('#app')
<!-- App.vue -->
<template>
<div class="par">
  //  直接使用 HeaderFrom 即可,不需要再次引入
  <HeaderFrom :name="name"></HeaderFrom>
 
  <Provide></Provide>
  <button @click="handleChangeName">父组件change name</button>
  </div>
</template>
<script setup>
import Provide from './components/provide1.vue'
import { ref, provide, inject } from 'vue'
let msg = ref('Andy start')
let name = ref('Andy')

const handleChangeName = () => {
  name.value = 'Andy change'
}
const sChangeName = () => {
  msg.value = 'Andy sChangeName'
}
provide('pName', {msg, sChangeName})
</script>

<style lang="scss">
.img-box{
  display: inline-block;
  width: 100px;
  height: 100px;
}
</style>

注意:如果声明的组件不是项目中绝大多数页面共用的,请勿注册全局组件,应为即使在页面中没有使用该组件,也会导致引入的组件被打包到打包后的文件中,无法通过 tree-shaking 自动移除,因为组件被挂载到app实例上;

tree-shaking:消除无用的js代码;
1、在webpack中,通过配置 optimization.usedExports: true,开启tree-shaking功能
2、在vite中,通过配置 rollup-plugin-commonjs,开启tree-shaking功能;

2.2. 局部组件

好处
1、可以非常清晰父子组件之间的依赖关系,便于维护;
2、同时只有在页面加载时候才会使用组件,可以更好的支持tree-shaking减少打包体积;
坏处
需要每次使用时候导入一次,增加文件的导入语句;

<!-- 定义局部组件 dialogForm.vue -->
<template>
<div class="dialog-container">
  <div class="dialog-form">
    <div class="dialog-header">
      <div class="dialog-title">新增用户</div>
      <el-icon class="dialog-close"><Close /></el-icon>
    </div>
    <el-form :model="formData" label-width="80px" ref="formDataRef">
      <el-form-item label="用户名:" prop="username">
        <el-input v-model="formData.username" placeholder="请输入用户名" />
      </el-form-item>
      <el-form-item label="职位:" prop="post">
        <el-input v-model="formData.username" placeholder="请输入职位" />
      </el-form-item>
      <el-button @click="submit" type="primary">提交</el-button>
    </el-form>
  </div>
</div>
</template>
<script setup>
import { reactive, ref } from 'vue'

const formDataRef = ref()
let formData = ref({
  username: '',
  post: ''
})

const submit = () => {
  console.log('==', formData.value)
}

</script>
<!-- 在父组件myComponents.vue 中引入使用 -->
<template>
  <div class="my-components">
      页面类型:{{pageNameType}}
      <DialogForm></DialogForm>
  </div>
  </template>
  <script setup>
  import { ref, reactive } from 'vue'
  // 在setup 中直接引入组件即可,打包编译时会自动编译成组件,不需要再次使用components
  import DialogForm from './dialogForm.vue'
  const pageNameType = ref('局部组件')
  </script>

2.3. 动态组件

动态组件,当一个页面中的内容需要通过不同的组件来进行展示时,可以通过动态组件的切换来实现;
需要注意的是:vue3中 需要使用markRaw() 或者 shallowReactive() 来创建组件,否则页面会发出警告,导致页面不更新
请添加图片描述

动态组件是通过 :is 属性来实现组件之间的切换的;

<component :is="组件名"></component>

如下实现:

<template>
  <div class="my-components">
      页面类型:{{pageNameType}}
      <component :is="comName"></component>
      <el-button type="primary" @click="handleChangeCom">切换组件</el-button>
  </div>
</template>
<script setup>
  import { ref, markRaw } from 'vue'
  import Work from './work.vue' // 组件内容: The job is GeYou's live.
  import UserInfo from './userInfo.vue' // 组件内容:用户信息
  const pageNameType = ref('动态组件')
  const workRaw = markRaw(Work) // 使用markRaw进行标记,避免转换为响应式对象
  const userInfoRaw = markRaw(UserInfo)
  let comName = ref(workRaw) // 默认展示组件为 Work
  const handleChangeCom = () => {
    console.log('===', comName)
    if (comName.value === workRaw) {
      comName.value = userInfoRaw
    } else {
      comName.value = workRaw
    }
  }
</script>

2.4. 递归组件

vue2 中是通过组件中的name属性来区分组件的,直接在自己组件中使用自己同名组件即可实现递归;
如:
递归组件注意需要有跳出循环的出口,不然会导致死循环,进而栈溢出; 跳出条件:v-if=“endNum < 4”
若不跳出循环将会报错:

请添加图片描述

<template>
  <div class="recursion-com" v-if="endNum < 4">
    <span>{{name}}--{{ num }}--{{ endNum }}</span>
      <div >
      // 此处调用直接与自己的组件名称保持一致即可
        <RecursionCom :num="endNum" ></RecursionCom> 
    </div>
  </div>
</template>
<script>
export default {
  name: 'RecursionCom', // 注意:需要声明组件名称
  components: {},
  props: {
    num: {
      type: Number,
      default: 0
    }
  },
  data() {
    return {
      name: 'vue2递归组件',
      list: [22, 33],
      endNum: 0
    }
  },
  created() {
    this.endNum = this.num
    this.endNum++
  }
}
</script>

vue3 中

父组件中:
<template>
<div>
  vue3 父组件
  <RecursionComV3 :data="data"></RecursionComV3>
</div>
</template>
<script setup>
import { ref } from 'vue'
import RecursionComV3 from './recursionComV3.vue';
// 声明一个data 变量数据
const data = ref([
  {
    id: '1-1',
    name: '张家',
    children: [
      {
        id: '1-1-2',
        name: '张三',
        children: [
          {
            id: '1-1-3',
            name: '张三郎',
          }
        ]
      }
    ]
  },
  {
    id: '1-2',
    name: '李家',
    children: [
      {
        id: '1-2-2',
        name: '李四',
        children: [
          {
            id: '1-2-3',
            name: '李四郎',
          }
        ]
      }
    ]
  }
])
</script>
<!-- 子组件中 -->
使用js 书写时:
<template>
<div class="my-recursion">
    <div v-for="(item, index) in props.data" :key="item.id">
      <div class="item">{{ item.id }}:{{item.name}}</div>
      <myTreeV3 v-if="item.children && item.children.length" :data="item.children"></myTreeV3>
    </div>
</div>
</template>
<script>
// 如果使用js 需要在子组件中使用export default{} 给组件命名name;
export default {
  name: 'myTreeV3', 
}
</script>
<script setup>
import { ref, reactive, toRefs, onMounted, watch, computed } from 'vue'
const props = defineProps({
  data: {
    type: Array,
    default: () => ([]),
  },
})
</script>

最终运行结果如下图
请添加图片描述

若子组件使用ts 书写:
注意:ts 中需要使用到递归组件,需要使用到递归类型,需要将数据类型进行声明,
同时 调用的递归组件名称 需要与 自己的文件名保持一致,否则不生效:比如文件名为recursionComV3Ts.vue,则调用时需要使用:

如下:

<template>
<div class="my-recursion">
    <div v-for="(item) in data" :key="item.id">
      <div class="item">{{ item.id }}:{{item.name}}</div>
      <!-- 使用ts 写递归组件时,调用的必须与自己的文件名保持一致 -->
      <recursionComV3Ts v-if="item?.children && item?.children?.length" :data="item?.children"></recursionComV3Ts>
    </div>
</div>
</template>
<script setup lang="ts">
// TreeData 声明接口类型
interface TreeData{
  id: string
  name: string
  children?:TreeData[] // children 是可以选项
}
defineProps<{
  data?:TreeData[]
}>()
</script>

3、组件的使用 注意事项

a、单文件组件结构、
b、命名规范,便于管理;
c、props属性传递声明类型,明确;
d、emit事件机制;
e、slot插槽,非常重要的部分,可以动态的将内容html插入到组件中;

下节 单独介绍 组件之间的传参,事件等

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1553075.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

信息系统项目管理师——第10章项目进度管理(重要)

本章节内容属于10大管理知识领域中的重中之重&#xff0c;选择、案例、论文都会考&#xff0c;需要完全掌握。 选择题&#xff0c;大概考3分左右&#xff0c;有的时候会考一点理论大多数都是考计算。 案例题&#xff0c;必考内容&#xff0c;各种类型的计算题&#xff0c;网络图…

基于SpringBoot的“招聘信息管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“招聘信息管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 系统首页界面图 企业招聘界面…

免费软件“蓝莓投屏”:支持多个Airplay同时镜像的投屏软件。

引言&#xff1a; 由于定制盒子(3288)不支持投屏功能&#xff08;有些5.1不支持&#xff0c;安卓4.X本身也不支持&#xff09;&#xff0c;需要借助第三方的投屏软件来实现这一需求。所以&#xff0c;研究半天&#xff0c;蓝莓投屏以其简便易用的特性脱颖而出&#xff0c;只需…

《QT实用小工具·二》图片文字转base64编码

1、概述 源码放在文章末尾 base64编码转换类 图片转base64字符串。base64字符串转图片。字符转base64字符串。base64字符串转字符。后期增加数据压缩。Qt6对base64编码转换进行了重写效率提升至少200%。 下面是demo演示&#xff1a; 项目部分代码如下所示&#xff1a; #ifn…

【漏洞复现】浙大恩特客户资源管理系统 Quotegask_editAction-sql接口处存在SQL注入漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

推动制药行业数字化转型:基于超融合架构的MES一体机解决方案

随着中国对信息化重视程度的不断加深&#xff0c;制药行业作为国民经济的重要支柱之一&#xff0c;也在积极寻求通过数字化手段提升产业效率与产品质量。自党的十六大提出“以信息化带动工业化”的战略以来&#xff0c;制药业的这一转型探索尤为迫切。 在现代制药生产中&#…

FPGA 图像边缘检测(Canny算子)

1 顶层代码 timescale 1ns / 1ps //边缘检测二阶微分算子&#xff1a;canny算子module image_canny_edge_detect (input clk,input reset, //复位高电平有效input [10:0] img_width,input [ 9:0] img_height,input [ 7:0] low_threshold,input [ 7:0] high_threshold,input va…

【漏洞复现】chatgpt pictureproxy.php SSRF漏洞(CVE-2024-27564)

0x01 漏洞概述 ChatGPT pictureproxy.php接口存在服务器端请求伪造 漏洞&#xff08;SSRF&#xff09; &#xff0c;未授权的攻击者可以通过将构建的 URL 注入 url参数来强制应用程序发出任意请求。 0x02 测绘语句 fofa: icon_hash"-1999760920" 0x03 漏洞复现 G…

element-ui 自定义点击图标/文本/按钮触发el-date-picker时间组件,不使用插槽

天梦星服务平台 (tmxkj.top)https://tmxkj.top/#/ 1. 图片预览 2.上代码 2.1html <el-button class"hide_input" size"small"><svg t"1711608996149" class"icon" viewBox"0 0 1024 1024" version"1.1"…

中国象棋AI在线对弈游戏源码

源码介绍 这是一款html5小游戏&#xff0c;主要功能在于js&#xff0c;带一套皮肤、内置ai算法&#xff0c;有能力的可以自行修改。 源码截图 下载地址 链接&#xff1a;https://pan.baidu.com/s/1fYp1HWsd91nJOdX1M8RFtQ?pwdh2iz 提取码&#xff1a;h2iz

最近Sentinel-2下载网站好像有点问题

最近Sentinel-2下载网站好像有点点问题&#xff0c;基本属于打不开的状态&#xff01; 这也难怪&#xff0c;Sentinel提供了全世界最好的免费遥感资源。其受欢迎程度可以想象的到&#xff01;这么多人访问网站&#xff0c;网站压力可以说是巨大的。这可是全世界的并发访问&…

快速上手Spring Cloud五:Spring Cloud与持续集成/持续部署(CI/CD)

快速上手Spring Cloud 一&#xff1a;Spring Cloud 简介 快速上手Spring Cloud 二&#xff1a;核心组件解析 快速上手Spring Cloud 三&#xff1a;API网关深入探索与实战应用 快速上手Spring Cloud 四&#xff1a;微服务治理与安全 快速上手Spring Cloud 五&#xff1a;Spring …

力扣 718. 最长重复子数组

题目来源&#xff1a;https://leetcode.cn/problems/maximum-length-of-repeated-subarray/description/ C题解&#xff08;思路来源代码随想录&#xff09;&#xff1a;动态规划 确定dp数组&#xff08;dp table&#xff09;以及下标的含义。dp[i][j] &#xff1a;以下标i - …

22.计算机中的数据存储

文章目录 一、计算机中的数据存储二、十进制1、十进制加法2、十进制减法 三、什么是二进制&#xff1f;二进制的运算过程 四、常见的进制五、计算机为什么要用二进制存储数据&#xff1f;六、进制之间的转换1、任意进制转十进制1&#xff09;二进制101转十进制8421快速转换法 2…

自动发卡平台源码优化版配套免签个人支付宝微信插件

这款免签个人支付宝微信插件&#xff0c;配套的是 自动发卡平台源码优化版&#xff0c;支持个人免签支付 其他系统的不支持&#xff01;

动态规划刷题(算法竞赛、蓝桥杯)--导弹拦截(线性DP)

1、题目链接&#xff1a;[NOIP1999 提高组] 导弹拦截 - 洛谷 #include <bits/stdc.h> using namespace std; const int N2e55; int a[N],x,n; int b[N],len;int main(){while(cin>>x)a[n]x;//求最长不上升子序列 b[0]2e9;//初始化为无穷大for(int i1;i<n;i){if(…

详细分析axios.js:72 Uncaught (in promise) Error: 未知错误 的解决方法(图文)

目录 1. 问题所示2. 原理分析3. 解决方法1. 问题所示 调试接口的时候,打开一个网页,在终端出现如下错误: axios.js:72 Uncaught (in promise) Error: 未知错误at __webpack_exports__.default (axios.js:72:1)截图如下所示: 2. 原理分析 点击浏览器的Bug出错: // 如果…

LLM之RAG实战(三十五)| 使用LangChain的3种query扩展来优化RAG

RAG有时无法从矢量数据库中检索到正确的文档。比如我们问如下问题&#xff1a; 从1980年到1990年&#xff0c;国际象棋的规则是什么&#xff1f; RAG在矢量数据库中进行相似性搜索&#xff0c;来查询与国际象棋规则问题相关的相关文档。然而&#xff0c;在某些情况下&#xff0…

设计模式 —— 设计原则

在软件开发中&#xff0c;为了提高软件系统的可维护性和可复用性&#xff0c;增加软件的可扩展性和灵活性&#xff0c;程序员要尽量根据6条原则来开发程序&#xff0c;从而提高软件开发效率、节约软件开发成本和维护成本。 开闭原则 对扩展开放&#xff0c;对修改关闭。在程序需…

0 决策树基础

目录 1 绪论 2 模型 3 决策树面试总结 1 绪论 决策树算法包括ID3、C4.5以及C5.0等&#xff0c;这些算法容易理解&#xff0c;适用各种数据&#xff0c;在解决各种问题时都有良好表现&#xff0c;尤其是以树模型为核心的各种集成算法&#xff0c;在各个行业和领域都有广泛的…