组件的了解

1、为什么封装组件

  1. 代码复用:通过封装,可以将一段代码或者功能模块封装为一个独立的组件,并在不同的项目或场景中重复使用。避免了代码的重复编写,提高了开发效率。
  2. 易于维护:将逻辑封装在单独的组件中可以使代码易于维护。当需要更改某个功能时,只需要修改组件内部的实现逻辑,而不需要修改其他部分。提高了代码的可维护性,降低了修改代码的风险。
  3. 可测试性:封装后的组件可以独立于其他代码进行测试,使得单元测试更容易进行,有助于代码质量。
  4. 提高可读性:封装组件可以使代码更加清晰易于理解。每个组件拥有明确的职责和接口,使得代码更加模块化,并且易于与其他开发者协作。

2、什么情况下封装组件

  1. 如果一块内容在项目中出现了两次就要考虑是否进行封装,一个组件、一个函数、一个css只要是需要多次使用的都可以考虑封装。

3、组件封装四要素

  1. props
    在封装组件时,props(属性)是一个重要的概念。props 允许你将数据从父组件传递到子组件,并在子组件中以某种方式使用这些数据。下面是一些关于封装组件时 props 的关键要点:

    (1)定义props:在react中,通常通过在组件的函数或类定义中指定propTypes和默认defaultProps来完成。
    (2)使用props:通过this.props(类组件)或函数参数(函数组件)来访问props。使用props来控制组件的渲染输出或行为。
    (3)传递props:在父组件中使用子组件时,可以通过JSX标签属性来传递props。
    (4)props只读:在react中,props是从父组件传递到子组件的,并且子组件不可以修改。
    (5)避免组件内部修改props:如果尝试在子组件内部修改props,React会发出警告,可能导致不可预测的行为。
    (6)props命名:使用有意义的props命名可以提高代码的可读性和可维护性。遵循驼峰命名法 (camelCase) 来命props
    

    下面是一个简单的例子,展示了如何在 React 组件中使用 props:

    // 子组件:Greeting
    function Greeting(props) {
      return <h1>Hello, {props.name}!</h1>;
    }
    
    Greeting.propTypes = {
      name: PropTypes.string.isRequired, // 指定 name 是一个必需的字符串类型的 props
    };
    
    // 父组件
    function App() {
      return (
        <div>
          <Greeting name="World" /> {/* 将 name prop 传递给 Greeting 组件 */}
        </div>
      );
    }
    
    
  2. slot
    在组件化开发的上下文中,slot(插槽)是一个常用于Vue.js框架中的概念,它允许你在子组件的模板中预留一些占位符,以便父组件可以插入自己的内容。这种机制增强了组件的复用性和灵活性。
    下面是一些关于 Vue.js 中 slot 的关键要点:

    (1)默认插槽:
    	用途:定义所有未明确指定的插槽的默认内容。
    	使用方法:在子组件中使用默认的<slot></slot>元素。
    	特性:最常用的的插槽类型,用于处理未明确指定插槽的默认内容。
    
    (2)命名插槽:
    	用途:允许开发人员为特定的内容指定一个名称,使插入更具有组织性。
    	使用方法:行<slot></slot>元素添加name属性来实现命名插槽。
    	特性:通过名称指定内容位置,使得父组件可以更有组织得插入内容。
    
    (3)作用域插槽:
    	用途:允许在插槽内访问组件的数据和方法,提供更高级的灵活性。
    	使用方法:通过#前缀创建插槽,并指定作用域插槽。
    	特性:允许在插槽内访问组件的数据和方法,提供更高级的灵活性。
    
    <template>
      <div>
        <h2>子组件标题</h2>
        <!-- 默认插槽 -->
        <slot></slot>
    
        <!-- 命名插槽 -->
        <slot name="header"></slot>
        <slot name="footer"></slot>
    
        <!-- 作用域插槽 -->
        <div>
          <slot name="scoped" :item="scopedData">
            <!-- 备用内容 -->
            <span>如果没有提供作用域插槽,将显示这里的内容</span>
          </slot>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          scopedData: { text: '这是作用域插槽的数据' }
        }
      }
    }
    </script>
    
    <template>
      <ChildComponent>
        <!-- 默认插槽内容 -->
        <p>这是默认插槽的内容</p>
    
        <!-- 命名插槽内容 -->
        <template v-slot:header>
          <h3>这是头部命名插槽的内容</h3>
        </template>
    
        <template v-slot:footer>
          <p>这是底部命名插槽的内容</p>
        </template>
    
        <!-- 作用域插槽内容 -->
        <template v-slot:scoped="{ item }">
          <p>{{ item.text }}</p>
        </template>
      </ChildComponent>
    </template>
    
    <script>
    import ChildComponent from './ChildComponent.vue'
    
    export default {
      components: {
        ChildComponent
      }
    }
    </script>
    
  3. event
    在封装组件时,event(事件)是一个重要的概念,它允许组件之间进行通信,特别是当子组件需要向父组件传递信息时。在前端框架中,如Vue.js和React,都有自己处理事件的方式。以下是两种框架中事件封装的简要说明和示例代码。

    Vue中的事件
    在vue中,子组件可以通过$emit方法触发一个自定义事件,并将数据作为参数传递给父组件。父组件在子组件标签上监听这个事件,并指定一个处理函数来接收数据。

    子组件:

    <template>
    	<button @click="notifyParent">通知父组件</button>
    </template>
    
    <script>
    	export default {
    		 methods: {
    			notifyParent() {
      			// 触发名为 'child-event' 的自定义事件,并传递数据
      				this.$emit('child-event', '来自子组件的消息');
    			}
    		}
    	}
    </script>
    

    父组件

    <template>
    	<ChildComponent @child-event="handleChildEvent" />
    </template>
    
    <script>
    import ChildComponent from './ChildComponent.vue';
    
    export default {
    	components: {
    		ChildComponent
    	},
    	methods: {
    		handleChildEvent(message) {
      			console.log(message); // 输出:来自子组件的消息
    		}
    	}
    }
    </script>
    

    React中的事件

    子组件

    import React from 'react';
    
    function ChildComponent({ onButtonClick }) {
      return (
        <button onClick={() => onButtonClick('来自子组件的消息')}>
          通知父组件
        </button>
      );
    }
    
    export default ChildComponent;
    

    父组件

    import React from 'react';
    import ChildComponent from './ChildComponent';
    
    function ParentComponent() {
      const handleButtonClick = (message) => {
        console.log(message); // 输出:来自子组件的消息
      };
    
      return (
        <div>
          <ChildComponent onButtonClick={handleButtonClick} />
        </div>
      );
    }
    
    export default ParentComponent;
    
  4. ref
    在React中,当封装组件时,我们可能希望外部组件能够访问到内部组件的DOM节点或实例。为了实现这一点,我们可以使用React.forwardRef来创建一个能够接收ref作为属性的组件。下面是一个封装组件并暴露ref的示例:

    函数组件中使用React.forwardRef

    import React, { forwardRef, useRef, useImperativeHandle, useEffect } from 'react';
    
    // 封装了一个带有focus功能的输入框组件
    const MyInput = forwardRef((props, ref) => {
      const inputRef = useRef();
    
      useImperativeHandle(ref, () => ({
        // 暴露focus方法给父组件
        focus: () => {
          if (inputRef.current) {
            inputRef.current.focus();
          }
        }
      }));
    
      return <input ref={inputRef} type="text" {...props} />;
    });
    
    // 使用示例
    function App() {
      const inputRef = React.createRef();
    
      const handleFocusButtonClick = () => {
        inputRef.current.focus(); // 调用封装的focus方法
      };
    
      return (
        <div>
          <MyInput ref={inputRef} placeholder="Click the button to focus" />
          <button onClick={handleFocusButtonClick}>Focus Input</button>
        </div>
      );
    }
    
    export default App;
    

    类组件中使用React.forwardRef

    import React, { forwardRef, Component } from 'react';
    
    class MyInput extends Component {
      inputRef = React.createRef();
    
      focus = () => {
        if (this.inputRef.current) {
          this.inputRef.current.focus();
        }
      };
    
      render() {
        return <input ref={this.inputRef} type="text" {...this.props} />;
      }
    }
    
    // 使用forwardRef来暴露ref
    const ForwardedMyInput = forwardRef((props, ref) => (
      <MyInput {...props} forwardedRef={ref} />
    ));
    
    // 注意:MyInput类组件内部需要做一些修改来接收forwardedRef并传递给内部的ref
    // ...(这里省略了修改MyInput的代码,因为直接修改MyInput不太直观)
    
    // 使用示例
    function App() {
      const inputRef = React.createRef();
    
      const handleFocusButtonClick = () => {
        inputRef.current.focus(); // 假设MyInput已经正确地将forwardedRef暴露为ref
      };
    
      return (
        <div>
          <ForwardedMyInput ref={inputRef} placeholder="Click the button to focus" />
          <button onClick={handleFocusButtonClick}>Focus Input</button>
        </div>
      );
    }
    
    export default App;
    
    // 注意:上面的示例代码省略了如何在MyInput内部处理forwardedRef的部分,
    // 因为直接修改MyInput类并不直观。在实际中,你可能需要修改MyInput的构造函数或生命周期方法来接收并处理forwardedRef。
    

4. 组件封装遵循什么特点

  1. 单一职责原则:
    (1)每个组件专注于一个特定的功能或UI部分,负责单一的页面渲染或逻辑处理。
  2. 低耦合、高内聚:
    (1)组件应有低耦合的特性,即组件之间的依赖关系应尽可能少,以便于修改和扩展。
    (2)同时组件内部功能应具有高内聚性,即组件内部的功能应机密相关,共同完成一个特定的任务。

5. 你封装过哪些组件

  1. UI组件:
    (1)按钮:用于触发某个动作或事件的界面元素
    (2)输入框:允许用户输入文本或数字的界面
    (3)对话框:用于显示信息、接受用户输入或执行操作的模态窗口
    (4)导航栏:用于页面间导航或页面内导航的页面元素

  2. 工具类组件:
    (1)日期选择器:允许用户选择日期的组件
    (2)颜色选择器:允许用户选择颜色的组件
    (3)文件上传组件:实现文件上传,通常包括选择文件、预览文件、和上传文件的操作
    (4)轮播图组件:用于展示多张图片或内容的循环滚动组件

  3. 业务相关组件:
    (1)表单组件:用于收集用户信息的复杂界面元素,可能包含多个输入框、选择框、按钮等。
    (2)数据表格:用于展示大量数据的表格组件,通常支持排序、筛选。分页等功能。
    (3)图表组件:用于展示数据的可视化组件,如柱状图、折线图。饼图。
    (4)地图组件:用于展示地理位置信息的组件,通常支持缩放、拖拽、标记等功能。

  4. 高级组件:
    (1)弹窗提示:用于显示短暂信息或提示信息的非模态窗口。
    (2)加载器:在数据加载或操作执行期间显示的界面元素,用于告知用户操作正在进行中。
    (3)拖拽组件:允许用户通过鼠标拖拽来调整元素位置或大小的组件。
    (4)树形控件:用于展示层次结构数据的组件,如文件目录、组织结构等。

6. 组件分成哪些种

  1. 按功能划分:
    (1)功能组件:实现特定功能或任务的组件,如表单处理、数据验证。这些组件封装了特定的算法、逻辑或业务流程,以提高开发效率和减少代码冗余。
    (2)界面组件:用户与系统进行交互的界面元素,如按钮、文本框、下拉菜单等。它们能够接收用户的输入,并将结果返回给系统。
    (3)数据组件:用于处理和管里数据的组件,如数据读取、存储、修改、删除等。它们可以与数据库、文件系统或其他数据存储设备进行交互。
    (4)通信组件:用于不同模块或系统之间的信息传递和交互,如基于HTTP、TCP/IP等通信协议的组件。
    (5)工具组件:提供辅助功能的组件,如日志记录、异常处理、配置管理。

  2. 按类型划分:
    (1)硬件组件:在计算机系统中,指组合计算机所需的硬件,如CPU、内存、硬盘等。
    (2)软件组件:自包含、可编程的、可重用的、与语言无关的软件单元。软件㢟的封装有助于实现软件重用和高度互操作性。

  3. 按使用场景划分:
    (1)基础组件:如导航栏、轮播图、对话框等,这些组件在多个应用中都有广泛的应用。
    (2)业务组件:针对特定业务逻辑或业务流程封装的组件,如订单处理、用户管理等。

  4. 按编程和软件开发分类:
    (1)复合组件:将现有的各种组件组合起来,形成一个新的组件,集中原有组件的性能。
    (2)扩展组件:在现有组件的基础上派生出一个新的组件,为原有组件增加新的性能或者更改原有组件的控能。
    (3)自定义组件:从特定基类或框架派生出来,满足特定需求或界面样式的组件

  5. 按界面元素分类:

    (1)导航类:如卡片、列表、网格、轮播、选项卡、菜单栏等,主要用于导航信息的展示和提示。
    (2)输入类:如文本框、下拉框、单选框、复选框等,用于用户输入信息。
    (3)信息类:如文本、图像、视频等,主要用于向用户传递信息。

  6. 按封装级别分类:
    (1)基本组件:如按钮、文本框等,是最小的、可重用的界面元素。
    (2)业务组件:由基本组件组合而成,实现特定业务功能的组件。
    (3)系统组件:由多个业务组件组合而成,实现整个系统功能的组件。

  • 28
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值