Vue3+ts+element-plus 组件的二次封装-- 头部搜索条件的封装

Vue 常用笔记

本人是一个web前端开发工程师,主要是vue框架,整理了一些Vue常用的技术,一方面是分享,一方面是做总结,今后也会一直更新,有好建议的同学欢迎评论区分享 ;-)

序号文章
0组件库展示
1通过JSON配置–头部搜索条件的封装组件
2通过JSON配置–表单Table的封装组件
3页脚的封装组件
4通过JSON配置–Form表单的封装组件
5生成npm组件库
6发布到npm
7vitest为组件库添加单元测试
8vuepress为组件库生成文档
9通过github或者gitee pages将组件库文档发布到线上,免费!
10源码地址

在这里插入图片描述


组件库开发流程

Vue组件库专栏会按顺序执行一下流程,不断完善组件库开发流程

  1. Vue3+element-plus+vite 组件的二次封装,封装了头部的搜索条件栏,tabel栏,分页栏,form表单,都设置成了通过json可配置项,方便复用;
  2. 封装好了就开始打包,并且进行本地测试;
  3. 组件库发布到npm;
  4. 添加vitest单元测试框架;
  5. 添加vuepress文档。


前言

环境状态
vue版本:vue3
是否使用 ts:是

后台管理系统的网站,一个页面无非就是4个常用业务块

  1. 头部的搜索栏
  2. table表格
  3. 页脚
  4. 新增编辑弹框

那咋们是不是可以将其进行封装成组件呢?
只需要传入一个配置文件就可以了~

项目解构如下:
在这里插入图片描述

封装后的展示图如下:
在这里插入图片描述

效果图如下:

在这里插入图片描述

如果能做成这样,是不是页面就会整洁很多?


头部搜索栏

原理:通过传递配置文件searchConfig(数组),遍历里面的数据,每一项都是一个element-UI组件。等需要触发搜索请求的时候,通过ref 获取到该组件的实例以及所需的searchData。

1. 效果图

在这里插入图片描述


2. 父组件

2.1 父组件 template 中的调用

<!-- 头部搜索栏 -->
 <PenkSearch ref="refPenkSearch" :searchConfig="searchConfig">
   <el-button type="primary" @click="getList">搜索</el-button>
   <el-button @click="handleAddItem">新增</el-button>
 </PenkSearch>

可以看到,只有简单的searchConfig配置,就可以了,其中2个button,是通过插槽默认是在搜索后面追加,样式也在组件中编码了,可以省掉很多步骤。


2.2. 父组件 script 中的调用

2.2.1 获取搜索组件中的查询对象queryObj

调用的时候就是根据获取的ref实例,使用暴露出来的对象里面的数据即可,主要代码就是下面两句…

const refPenkSearch = ref();
…refPenkSearch.value.queryObj

// 搜索框ref实例
const refPenkSearch = ref();
// 表格数据
let tableData = reactive([]);
// 查找数据
async function getList() {
  // 清空数据
  tableData.length = 0;
  console.log("tableData1:", tableData);

  // 判断是否有对象,没有的话就自动弄
  let res = await http.getList({
    ...refPenkSearch.value.queryObj,
    pageNum: paginationData.pageNum,
    pageSize: paginationData.pageSize,
  });
  // @ts-ignore
  tableData.push(...res.rows);
  paginationData.total = res.count;

  console.log("tableData:", tableData);
}

tips:这边要注意reactive 创建的tabelData,不能使用直接赋值,因为是个proxy对象~


2.2.2 使用的配置

这边有的配置是可填可不填的,具体的配置项可以看封装组件里面的参数,这边大概看一下

  • type:类型,判断是什么UI组件
  • prop:很关键的,用来绑定该UI组件对应属性名!!!
  • data:用来存放可选的UI组件的配置,比如下拉框,级联之类...
  • label:在UI组件前面的label
  • width:UI组件的宽度
  • hidden:是否隐藏,有些业务需求是根据不同角色,一些是不展示的
  • clearabel:是否可清空数据
 const searchConfig = [
  {
    type: "select",
    label: "父级用户类型",
    width: 150,
    prop: "parentId",
    hidden: false,
    clearable: true,
    data: [],
  },
  {
    type: "input",
    label: "类型名",
    placeholder: "请输入类型名",
    width: 150,
    clearable: true,
    prop: "typeName",
    hidden: false,
  },
  {
    type: "select",
    label: "是否查找软删除",
    placeholder: "请选择",
    width: 150,
    prop: "paranoid",
    hidden: false,
    clearable: true,
    data: [
      {
        value: 0,
        label: "是",
      },
      {
        value: 1,
        label: "否",
      },
    ],
  },
];

3. 组件的封装

3.1 封装组件template

3.1.1 请求组件的配置
  1. searchConfig:是个对象数组,用于遍历出一个个请求需要的组件,目前只列出了input跟select,可按需增加。
  2. searchConfig.data:用来给那些可选的组件,比如select或者级联…
  3. queryObj:是封装组件内的一个reactive对象,并且通过defineExpose 暴露给了父组件。
  4. searchConfig.props是每一项的键名,queryObj通过字符串索引的方式,将至设置成键名,并且通过v-model将键值绑定到该每一项的UI组件上。
<template v-for="item in props.searchConfig" :key="item.prop">
  <div
    class="penk-search-item"
    v-if="item.hidden != true"
  >
    <span>{{ item.label }}:</span>
    <!-- 输入框 -->
    <el-input
      v-if="item.type == 'input'"
      v-model="queryObj[item.prop]"
      :placeholder="item.placeholder || ''"
      :clearable="item.clearable"
      :disabled="item.disabled"
      :style="{ width: item.width + 'px' }"
    />
    <!-- 下拉框 -->
    <el-select
      v-else-if="item.type == 'select'"
      v-model="queryObj[item.prop]"
      :placeholder="item.placeholder || ''"
      :clearable="item.clearable"
      :disabled="item.disabled"
      filterable
      :style="{ width: item.width + 'px' }"
    >
      <el-option
        v-for="option in item.data"
        :key="option.value"
        :label="option.label"
        :value="option.value"
      />
    </el-select>
  </div>
</template>

3.1.2 预留的插槽

主要用于存放按钮,比如添加,查询按钮…

<!-- 默认尾部插槽 -->
<div class="penk-search-footer">
  <slot></slot>
</div>

3.2 封装组件script

3.2.1 props属性的配置

由于使用了TS来编码,咋们可以在组件中interface中写清楚一些配置,方便使用者知道有什么配置 :)

// 这边主要是申明了是个对象数组,并且每个对象定义是按照searchItem这个接口来的
interface Props {
  searchConfig: searchItem[];
}
// 每一个搜索条件对应的一些参数
interface searchItem {
  // 必填
  // 标签名
  label: string;
  // 组件所需类型,下拉框或者输入框
  type: string;
  // 对应的属性名 如: queryObj.name ~
  prop: string;

  // 选填-通用
  // 宽度
  width?: number;
  // 占位符
  placeholder?: string;
  // 是否清空
  clearable?: boolean;
  // 是否使能
  disabled?: boolean;
  // 是否隱藏
  hidden?: boolean;

  // 选填-特殊
  // 数据,一般是下拉框之类需要可选项的才用到
  data?: any;
}
3.2.2 组件内的queryObj变量
interface queryObj {
  [index: string]: any;
}

// queryObj 就是一个搜索条件的对象,里面每一个属性就是一个搜索条件
// 设置私有属性,防止被修改~
const queryObj = reactive<queryObj>({});

// 将queryObj暴露出去,父组件才可以调用
defineExpose({
  queryObj,
});

总结

  1. 封装很简单,关联性不强,通过searchConfig传递给子组件,就可以生成相应的头部搜索栏视图。
  2. 搜索栏的操作,只会同步到组件内的queryObj对象。
  3. 父组件想要获取queryObj的时候,只需通过ref获取即可…

当然,你也可以实现双向绑定的功能,但是每一个父组件,是不是都要声明一个变量呢?这个变量好像也没什么其他的用处了...


源码

<!--
 * @Author: Penk
 * @LastEditors: Penk
 * @LastEditTime: 2022-11-29 13:31:21
 * @FilePath: \front-master\src\components\public\PenkSearch.vue
 * @email: 492934056@qq.com
-->
<template lang="">
  <div class="penk-search-box">
    <!-- 头部插槽 -->
    <slot name="header"></slot>
    <template v-for="item in searchConfig" :key="item.prop">
      <div
        class="penk-search-item"
        :style="{ display: item.hidden == true ? 'none' : '' }"
      >
        <span>{{ item.label }}</span>
        <!-- 输入框 -->
        <el-input
          v-if="item.type == 'input'"
          v-model="queryObj[item.prop]"
          :placeholder="item.placeholder || ''"
          :clearable="item.clearable"
          :disabled="item.disabled"
          :style="{ width: item.width + 'px' }"
        />
        <!-- 下拉框 -->
        <el-select
          v-else-if="item.type == 'select'"
          v-model="queryObj[item.prop]"
          :placeholder="item.placeholder || ''"
          :clearable="item.clearable"
          :disabled="item.disabled"
          filterable
          :style="{ width: item.width + 'px' }"
        >
          <el-option
            v-for="option in item.data"
            :key="option.value"
            :label="option.label"
            :value="option.value"
          />
        </el-select>
      </div>
    </template>

    <!-- 默认尾部插槽 -->
    <div class="penk-search-footer">
      <slot></slot>
    </div>
  </div>
</template>

<script setup lang="ts">
import { reactive } from "vue";

// 每一个搜索条件的对象
interface queryObj {
  [index: string]: any;
}

// 申明是个搜索条件的对象
interface searchItem {
  // 必填
  // 标签名
  label: string;
  // 组件所需类型,下拉框或者输入框
  type: string;
  // 对应的属性名 如: queryObj.name ~
  prop: string;

  // 选填-通用
  // 宽度
  width?: number;
  // 占位符
  placeholder?: string;
  // 是否清空
  clearable?: boolean;
  // 是否使能
  disabled?: boolean;
  // 是否隱藏
  hidden?: boolean;

  // 选填-特殊
  // 数据,一般是下拉框之类需要可选项的才用到
  data?: any;
}

interface Props {
  searchConfig: searchItem[];
}

// 定义props
let props = defineProps<Props>();

// 设置私有属性,防止被修改~
const queryObj = reactive<queryObj>({});

// 将queryObj暴露出去,父组件才可以调用
defineExpose({
  queryObj,
});
</script>

<style lang="less" scoped>
.penk-search-box {
  margin-bottom: 10px;
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;

  .penk-search-item {
    margin-right: 20px;
    margin-bottom: 10px;
  }

  .penk-search-footer {
    margin-bottom: 10px;
    & > {
      margin-right: 20px;
    }
  }
}
</style>


  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Vue2中,对于element-ui组件二次封装,可以按照以下步骤进行: 1. 需求分析:明确需要封装element-ui组件,以及需要添加的功能和配置项。 2. 创建父组件:编写父组件的template和script代码,其中template中调用封装组件,script中定义需要传递给封装组件的props属性。 3. 创建封装组件:编写封装组件的template和script代码。在template中使用element-ui组件,并根据需要进行样式和布局的调整。在script中定义props属性,接收父组件传递的值,并监听element-ui组件的事件,触发update事件给父组件。 4. 通过临时变量传递值:由于父组件传递给封装组件的props不能直接作为封装组件的v-model属性传递给element-ui组件,所以需要在封装组件中定义一个临时变量来存储值,并将该变量与element-ui组件进行绑定。 5. 完成打通:在封装组件中监听中间件,接收到element-ui组件的update事件后,再将该事件传递给父组件。 总结来说,Vue2中对于element-ui组件二次封装,需要创建父组件封装组件,通过props属性传递值,并在封装组件中监听element-ui组件的事件并触发update事件给父组件。同时,需要使用临时变量来传递值给element-ui组件。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Vue3+ts+element-plus 组件二次封装-- 页脚分页el-pagination的二次封装](https://blog.csdn.net/cs492934056/article/details/128096257)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Penk是个码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值