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

2023-11-07

Vue 常用笔记

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

Vue专栏:点击此处
Vue组件库专栏:点击此处
Vue2 vs Vue3 专栏:点击此处
Typescript专栏:点击此处

在这里插入图片描述


组件库开发流程

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>


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • 主干视图 DOM 元素已删除

    我一直在阅读有关 Backbone js 僵尸 或内存泄漏 问题的信息 基本上 当您不再需要该元素时 您必须从 DOM 中解除绑定并删除该元素 以确保所有事件也被删除 现在 我有一个包含几个容器的单页应用程序 div div div div
  • 如何测试 javascript 闭包内的函数

    这似乎是不可能的 也可能是 但我正在尝试更多的 TDD 但我总是在闭包方面碰壁 假设我有以下内容 function createSomething init function privateMethod param return init
  • React js Stripe 结账不起作用

    我正在尝试在 React js 应用程序中呈现条带结账默认表单
  • 了解设置 JQuery 变量

    了解设置 JQuery 变量 最近 我通过在 StackOverflow 上遇到的另一个问题寻找帮助 了解到如何设置 JQuery 变量 如下所示 您可以通过简单地调用变量来创建输入字段 并且锚变量似乎也定义了样式 var clicked
  • Android 设备上的 PhoneGap 蓝牙插件

    我一直在尝试让 PhoneGap 工作的蓝牙插件 但我似乎不知道哪里出了问题 首先 我的测试设备是 Galaxy S3 GT 19305T 应用程序是使用PhoneGap CLI http docs phonegap com en 3 0
  • jquery.find() 可以只选择直接子项吗?

    我应该向 jQuery find 提供什么参数来选择元素子元素而不选择其他元素 我不能用 gt 引导选择器 而用 将选择所有后代 而不仅仅是直接子代 我知道 jQuery children 但这是一个库 因此用户能够提供自己的选择器 并且我
  • 在 Vue.js 中从父组件执行子方法

    目前 我有一个 Vue js 组件 其中包含其他组件的列表 我知道使用 vue 的常见方式是将数据传递给孩子 并从孩子向父母发出事件 但是 在这种情况下 我想在子组件中的按钮出现时执行子组件中的方法 parent被点击 哪种方法最好 一种建
  • 如何重置使用 JavaScript 更改的 CSS 属性?

    我的导航按钮的宽度从 100px 增加到 150px 当鼠标悬停在 nav li hover width 150px 但是使用 javascript 我已经做到了 无论选择哪个选项 宽度都将继续为 150px 当选择每个选项时 它会使其他选
  • 检查 JavaScript 字符串是否为 URL

    JavaScript 有没有办法检查字符串是否是 URL 正则表达式被排除在外 因为 URL 很可能是这样写的stackoverflow 也就是说它可能没有 com www or http 如果你想检查一个字符串是否是有效的 HTTP UR
  • 从未用 @flow 标记的导入文件中获取类型定义

    TL DR我怎么告诉flow从未声明的导入模块导入类型定义 flow 加长版 流接缝能够从不使用流语法的文件中派生类型 请参阅示例 示例文件 flow js if Math random lt 0 5 var y hello else va
  • 为什么是 javascript:history.go(-1);无法在移动设备上工作?

    首先 一些背景 我有一个向用户呈现搜索页面 html 表单 的应用程序 填写标准并单击 搜索 按钮后 结果将显示在标准部分下方 在结果列表中 您可以通过单击将您带到新页面的链接来查看单个结果的详细信息 在详细信息页面中 我添加了一个 返回结
  • 音频 blob 的 URL.createObjectURL 在 Firefox 中给出 TypeError

    我正在尝试从创建的音频 blob 创建对象 URLgetUserMedia 该代码在 Chrome 中可以运行 但在 Firefox 中存在问题 错误 当我打电话时stopAudioRecorder 它停在audio player src
  • 在 webpack 2.x 中使用 autoprefixer 和 postcss

    如何使用autoprefixer使用 webpack 2 x 以前 它曾经是这样的 module loaders test scss loader style css sass postcss postcss gt return autop
  • 通过 CDN 使用 Dojo 时如何加载自定义 AMD 模块?

    我正在使用 google 的 CDN 并尝试使用他们的加载程序加载我自己的 AMD 模块 我知道我做错了什么 但我被困住了 有任何想法吗
  • 如何使输入字段和提交按钮变灰

    我想变灰这两件事 http doorsplit heroku com 歌曲输入字段和提交按钮 直到用户输入艺术家 有没有一种简单的方法可以通过 JQuery 来做到这一点 艺术家输入字段的id是 request artist 你可以这样做
  • Firefox 书签探索未超过 Javascript 的第一级

    我已经编写了一些代码来探索我的 Firefox 书签 但我只获得了第一级书签 即我没有获得文件夹中的链接 e g 搜索引擎 雅虎网站 谷歌网站 在此示例中 我只能访问 Search engines 和 google com 不能访问 yah
  • Angular 2+ 安全性;保护服务器上的延迟加载模块

    我有一个 Angular 2 应用程序 用户可以在其中输入个人数据 该数据在应用程序的另一部分进行分析 该部分仅适用于具有特定权限的人员 问题是我们不想让未经授权的人知道how我们正在分析这些数据 因此 如果他们能够在应用程序中查看模板 那
  • 如何在类似控制台的环境中运行 JavaScript?

    我正在尝试遵循这里的示例 http eloquentjavascript net chapter2 html http eloquentjavascript net chapter2 html and print blah 在浏览器中运行时
  • 有没有办法阻止 prettier / prettier-now 将函数参数分解为新行

    当使用 prettier prettier now 在保存时进行格式化时 当一个函数包装另一个函数时 它会中断到一个新行 我想知道是否有办法阻止这种行为 例如 期望的输出 app get campgrounds id catchAsync
  • 为什么 jquery 没有检测到单选按钮未被选中的情况? [复制]

    这个问题在这里已经有答案了 可能的重复 JQuery radioButton change 在取消选择期间不会触发 https stackoverflow com questions 5176803 jquery radiobutton c

随机推荐

  • css的标准写法,前端css书写规范

    代码书写规范这种东西虽然不是必须的但是确实很有必要的好的书写规范不单单能增加可阅读性和提高代码性能而且有利于后续人员维护代码 良好的书写规范也是区分新手与专业人员的一个标准 一css书写顺序 1 位置属性position top right
  • VUE项目引入微信jssdk

    我们的一个vue webpack的 SPA项目需要在微信中使用 因此需要导入微信的jssdk库 通过搜索发现npm有微信jssdk的依赖包 weixin js sdk 于是 导入依赖包 npm i S weixin js sdk 前端页面U
  • Log 利用装饰模式 打印增强

    包引用
  • 前端基础--JavaScript

    一 JavaScript介绍 虽然是java作为前缀 但java和javascript的关系 就像老婆和老婆饼之间的关系 没有一毛钱关系 网景公司在Netscape2 0首先推出了JavaScript JavaScript 的正式名称是 E
  • Windows应急响应

    临近冬奥 残奥 发一篇Windows的应急响应 希望对大家有所帮助 下一篇会发Linux的应急响应 目录 Part1 前期交互 Part2 主机排查 Part3 工具篇 Part1 前期交互 这个阶段主要是先找客户了解主机的基本情况 如 主
  • Push failed Remote: Support for password authentication was removed on August 13, 2021.

    啥情况 竟然不能推送代码到github了 还能不能愉快的玩耍了 报错如下 大概意思就是 8月13后 不能使用用户名 密码的形式进行Push 强制大家改成SSH的方式 先说解决方案吧 一 查看是否已有密钥 Mac Users Your Nam
  • 写好“提示”改变“智造未来”-GPT4提示词驶入代码优化驾驶座心得

    开篇 在前端科技的新浪潮中 Artificial Intelligence AI 的逐渐成熟与发展引领着我们向前 其中OpenAI的GPT4提供了我们一种新的可能 帮助我们优化代码 使编程变得更加轻松 在这篇文章中 我们将一同探究如何在1
  • C++ 之 模板与泛型编程(二、模板实例化)

    模板是一个蓝图 它本身不是类或函数 编译器用模板产生指定的类或函数的特定类型版本 产生模板的特定类型实例的过程称为实例化 模板在使用时将进行实例化 类模板在引用实际模板类类型时实例化 函数模板在调用它或用它对函数指针进行初始化或赋值时实例化
  • 【UBUNTU与ROS实战笔记】(二)——系统ROS安装与配置

    本文结构 0 引言 1 ROS系统安装 1 1 解析安装过程 1 2 ROS环境配置 小结 该博文是 UBUNTU与ROS实战笔记 系列的第二篇文章 写这个的过程中我也正一步一步的实际操作 如果你对该内容有兴趣 欢迎留言交流 0 引言 同学
  • 死锁/死锁的实现

    首先明白死锁产生的原因 死锁指两个或两个以上线程执行过程中 因争夺资源而造成的互相等待现象 四个必要条件 1 互斥性 线程对资源的占有是排他性的 一个资源只能被一个线程占有 直到释放 2 请求和保持条件 一个线程对请求被占有资源发生阻塞时
  • Unity上架苹果商店游戏资源加载的问题被拒4.2.3

    由于游戏资源加载的问题被4 2 3拒绝的解决方案 方案一 加一个下载资源说明 然后改一下逻辑 启动app可以正常进去 然后提醒用户在你进去体验的初期 我们会继续在Wi Fi环境下继续下载app需要的资源 方案二 真是本地解压资源 可以搞一个
  • 前端笔记目录

    HTML 部分 HTML 常用的标签 HTML 表格标签 HTML 列表标签 HTML 表单标签 CSS 部分 CSS 选择器 CSS 字体属性 JavaScript 部分 JavaScript ES6新特性 1 JavaScript ES
  • 简单的spring项目搭建流程

    一 搭建步骤 创建空maven项目 pom文件导入相应依赖jar包 创建包结构 domain test即可 创建JavaBean配置文件 编写简单示例 二 开始 1 创建一个空的maven项目 2 在pom xml文件中导入spring5依
  • AI小程序——文本绘图

    文章目录 一 摘要 二 文心 ERNIE ViLG 技术原理解读 图文双向生成统一建模 三 使用教程 2 1 exe下载 2 2 获取API 2 3 软件使用 2 4 源码链接 一 摘要 在文字生成图像上 文心 ERNIE ViLG 可以根
  • 力扣第99场双周赛题目记录(复盘)

    第一题 2578 最小和分割 给你一个正整数 num 请你将它分割成两个非负整数 num1 和 num2 满足 num1 和 num2 直接连起来 得到 num 各数位的一个排列 换句话说 num1 和 num2 中所有数字出现的次数之和等
  • 解决 VMware 克隆或复制的虚拟机,同时只有一台能上网问题

    VMware 克隆或复制虚拟机后 发现不能上网 多次调试后 确定是克隆或复制的虚拟机与原虚拟机 同时只能有一台能上网 原因是 克隆或复制的虚拟机 网卡 MAC 地址一样导致 重新分配的新 MAC 地址即可 方法如下 1 打开 Vmware
  • Matlab/Simulink-单相逆变电路双闭环仿真搭建

    1 前言 Simulink零基础 单相逆变电路双闭环仿真搭建 单相逆变电路仿真 单相逆变仿真 十分钟让你掌握单相电路简单的双闭环控制 本文不讲单相逆变电路的原理和构成 只涉及如何在Simulink中实现单相逆变电路 搭建的过程在下面视频里了
  • Unity射线穿透UI解决

    unity场景中 射线是可以穿透UI的 我用过很多版本 都有这个问题 比如我现在用2020版本的unity做了个范例 我在场景中新建了一个cube名叫 我秦始皇打钱 点击这个物体就会出现log显示这个物体的名字 代码在下面 运行之后确实会弹
  • 计算机原码补码和反码的计算方法,一个数的原码,反码,补码怎么算,原码 反码 补码...

    数在计算机中是以二进制形式表示的 数分为有符号数和无符号数 原码 反码 补码都是有符号定点数的表示方法 一个有符号定点数的最高位为符号位 0是正 1是副 以下都以8位整数为例 原码就是这个数本身的二进制形式 例如 0000001 就是 1
  • Vue3+ts+element-plus 组件的二次封装-- 头部搜索条件的封装

    Vue 常用笔记 本人是一个web前端开发工程师 主要是vue框架 整理了一些Vue常用的技术 一方面是分享 一方面是做总结 今后也会一直更新 有好建议的同学欢迎评论区分享 Vue专栏 点击此处 Vue组件库专栏 点击此处 Vue2 vs