vue封装组件进阶

创作代码时,经常会遇到需求出现相似的界面效果,但是里面循环的列表参数不一致,重新写的话会导致代码冗余。复用代码,灵活操控会大大提高开发效率。

场景:vue循环列表,两个列表展示的参数不一致;封装一个公用组件,达到可定制会展示内容

初效果

原始代码

html 复制代码
<div class="test_item">
      <div class="test_item_top">
        产品信息
      </div>
      <div class="product">
        <div v-for="(item,index) in product" :key="index" class="product_item">
          <div class="product_item_top">
            产品名称
          </div>
          <div class="product_item_bottom">
            {
  
  { item.productname }}
          </div>
          <div class="product_item_top">
            生产地
          </div>
          <div class="product_item_bottom">
            {
  
  { item.address }}
          </div>
        </div>
      </div>
    </div>
html 复制代码
<div class="test_item">
      <div class="test_item_top">
        审核信息
      </div>
      <div class="product">
        <div v-for="(item,index) in history" :key="index" class="product_item">
          <div class="product_item_top">
            提交时间
          </div>
          <div class="product_item_bottom">
            {
  
  { item.one }}
          </div>
          <div class="product_item_top">
            审核时间
          </div>
          <div class="product_item_bottom">
            {
  
  { item.two }}
          </div>
        </div>
      </div>
    </div>

可见,两个列表有相似的样式,可以公用一个组件。

初次封装可能就会把共同使用的html及css代码剪切到一个子组件中,通过父组件给子组件的传值来达到渲染的效果;但数据和效果上可以看出这是两个表格,数据也是两个。

如果是这样的话,首先想到的是在父组件挂载两个子组件不就行了,传递不同的数据用以渲染;

html 复制代码
<template>
  <div class="test">
    <product :infor="productInfor" />
    <history :infor="historyInfor" />
  </div>
</template>

这样写违背了我们的初衷,果断舍弃

再者要不把数据全部给子组件,子组件根据渲染条件判断?这样写不就是相当于把冗余的代码剪切到另外的文件吗!!

进阶

首先,我们需要解决一个问题就是效果图上的诸如产品名称、生产地、提交时间等固定的文字能否也是动态的,根据我们传入的数据来一一展示呢?!固定文字与渲染数组的对象的键一一对应,那就是对象了。

我们平常都是循环数组对象已达到在页面上渲染诸多相同结构的数据

html 复制代码
<div v-for="(item, index) in history" :key="index" class="product_item">
    <div class="product_item_top">
        提交时间
    </div>
    <div class="product_item_bottom">
        {
  
  { item.one }}
     </div>
     <div class="product_item_top">
         审核时间
     </div>
     <div class="product_item_bottom">
         {
  
  { item.two }}
      </div>
</div>

其实对象也可以用作循环遍历的,在上面的循环里在写入循环对象。用对象的键值来展示固定字段,用对象的键来固定展示外层数组数据

html 复制代码
data() {
      return {
        obj: {
          productname: '产品名称',
          address: '生产地'
        }
      }
    }
html 复制代码
<div class="product">
      <div
        v-for="(item, index) in product.data"
        :key="index"
        class="product_item"
      >
        <div v-for="(it, objIndex) in obj" :key="objIndex">
          <div class="product_item_top">
            {
  
  { it }}
          </div>
          <div class="product_item_bottom">
            {
  
  { item[objIndex] }}
          </div>
        </div>
      </div>
    </div>

注释:上方代码中循环对象,第一个参数为对象的键值,第二的参数为对象的键,根据循环对象的键来获取循环数组对象的规定值

结合以上的规则,我们可以对代码进行再升级

父组件

html 复制代码
<template>
  <div class="test">
    <list :product="product" :obj="proObj" />
    <list :product="history" :obj="hisObj" />
  </div>
</template>
<script>
  import list from './components/list.vue'
  export default {
    components: {
      list
    },
    data() {
      return {
        product: {
          category: '产品信息',
          data: [
            {
              productname: '肯德基',
              address: '洛杉矶'
            },
            {
              productname: '蜜雪冰城',
              address: '中国'
            }
          ]
        },
        proObj: {
          productname: '产品名称',
          address: '地址'
        },
        history: {
          category: '历史记录',
          data: [
            {
              one: '2025-05-05 12:00:00',
              two: '2025-06-05 12:00:00'
            },
            {
              one: '2025-06-05 12:00:00',
              two: '2025-07-05 12:00:00'
            }
          ]
        },
        hisObj: {
          one: '提交时间',
          two: '审核时间'
        }
      }
    }
  }
</script>

子组件

html 复制代码
<template>
  <div class="test_item">
    <div class="test_item_top">
      {
  
  { product.category }}
    </div>
    <div class="product">
      <div
        v-for="(item, index) in product.data"
        :key="index"
        class="product_item"
      >
        <div v-for="(it, objIndex) in obj" :key="objIndex">
          <div class="product_item_top">
            {
  
  { it }}
          </div>
          <div class="product_item_bottom">
            {
  
  { item[objIndex] }}
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
  export default {
    props: {
      product: {
        type: Object,
        default: () => {}
      },
      obj: {
        type: Object,
        default: () => {}
      }

    },
    data() {
      return {

      }
    }
  }
</script>

由此可以看出,子组件完全根据父组件的要求展示内容,完全灵活。

实际使用中,样式完全一致的情况很少,有些地方会有些不同,那就需要我们对组件进行再升级。

vue中插槽的作用完全可以满足我们的需求,在不影响我们的总体效果。在 Vue.js 中,插槽(Slots)是一种非常强大的组件内容分发机制,允许你在父组件中向子组件传递自定义内容。插槽的主要作用是提高组件的灵活性和复用性。

效果图

父组件修改的内容

html 复制代码
<list :product="product" :obj="proObj">
      <template v-slot:category="slotProps">
        <div class="btn_cate">
          <div class="btn_inner">
            {
  
  { slotProps.item.address }}
          </div>
        </div>
      </template>
</list>

子组件修改的内容

html 复制代码
    <div class="product">
      <div
        v-for="(item, index) in product.data"
        :key="index"
        class="product_item"
      >
        <div v-for="(it, objIndex) in obj" :key="objIndex">
          <div class="product_item_top">
            {
  
  { it }}
          </div>
          <div class="product_item_bottom">
            {
  
  { item[objIndex] }}
          </div>
        </div>
        <template>
          <slot name="category" :item="item"></slot>
        </template>
      </div>
    </div>

以上就是所有内容

本博客仅仅是提供了一种优化组件封装的思路,欢迎留言交流

相关推荐
bin915325 分钟前
DeepSeek与Vue.js组件开发:解锁AI与前端开发的融合密码
vue.js·deepseek
禁默32 分钟前
【学术投稿-第六届新材料与清洁能源国际学术会议(ICAMCE 2025)】组织与结构:HTML中的<fieldset>与<legend>标签解析
前端·html
南城巷陌32 分钟前
Node.js的API之dgram的用法详解
前端·node.js·dgram
不会&编程33 分钟前
第3章 使用 Vue 脚手架
前端·javascript·vue.js
ttod_qzstudio36 分钟前
基于Typescript,使用Vite构建融合Vue.js的Babylon.js开发环境
vue.js·typescript·babylon.js
杨晓风-linda38 分钟前
Angular-hello world
前端·javascript·angular.js
一只理智恩38 分钟前
Cesium 离线加载瓦片图
前端·javascript·arcgis
幸福右手牵1 小时前
WPS如何接入DeepSeek(通过JS宏调用)
javascript·人工智能·深度学习·wps·deepseek
115432031q1 小时前
基于SpringBoot养老院平台系统功能实现十一
java·前端·后端
AC-PEACE1 小时前
route 与 router 之间的差别
前端·网络