页面小组件-搜索栏(二)-未经项目验证,慎重!!!

news2024/9/24 15:17:58

前言说明

这一版是未经过项目验证的,可能会有地方需要自行调整,如需使用,请慎重、慎重、再慎重!!!

前言追溯

前面分享过的搜索栏组件是一个临时产物,经历了一两个项目之后就被淘汰了。后续在我们前端小组内部开始探讨一种新的页面开发模式:配置渲染。理想状态下,仅需要在页面中建立一个配置对象以及配套的各种处理方法,就可以渲染出一个页面。大概内容如下:

<template>
  <custom-component ref="customRef" :config="comConfig"/>
</template>
<script>
  name: 'XXX',
  data(){
    return {
      comConfig: {
        // 标题栏配置
        headerConfig: {
          title: 'xxx',
          buttonList: [...]
        }
        // 搜索栏配置
        searchConfig: [...]
        // 表格配置
        tableConfig: {
          proxyConfig: {...},
          columns: [....],
          pagination: {...}
        },
        modalConfig: {
          title: 'xxx',
          visible: false,
          formInfo: {...},
          formRules: {...}
        }
      }
    }
  }
</script>

我当时第一感觉:这个构想确实牛的一批!但咋实现出来呢?,这哪是封组件,这就是封装了一个公司内部通用的基于element-ui二次开发的插件库啊这是。最开始只是讨论想法,并没有开始进行实现,也就不关我事,全身心的投入项目需求开发中了。

没想到的是,不就之后的一天,领导发给我了一个项目:你没事的时候看看项目代码,梳理下内容,尽快整理出来个内容的文档,后面有一个项目可能会使用这个项目作为组件去开发。

我花费一天时间把代码大概过了一遍,猛的发现:当时提出的构想,这不就是已经实现了一大半了嘛!!!后续也是由我把代码做了一些修改,更加适合项目中使用,后续也确实是在项目中进行了试用,有用的很好很舒服的地方,也有极其不想用的地方。整理出来的帮助文档,后续也作为培训资料进行了内部培训…

打住,就此打住!这是我后面要分享的内容,此处先不多说。

样例展示

默认状态

在这里插入图片描述

展开状态

在这里插入图片描述

折叠状态

在这里插入图片描述

组件示例

<SearchCustom
  ref="searchCustom"
  :itemList="searchItemList"
  @formSearch="handleSearch"
  @formReset="handleReset"
/>

searchItemList: [
  {
    elType: "el-input",
    key: "name",
    placeholder: "请输入风险词模糊搜索"
  },
  {
    elType: "el-select",
    key: "sex",
    placeholder: "请选择性别",
    options: []
  },
  {
    elType: "el-cascader",
    key: "dept",
    placeholder: "请选择部门",
    options: [
      {
        label: '研发部',
        value: 'yanfa',
        children: [
          {
            label: '研发一组',
            value: 'yanfa1',
          },
          {
            label: '研发二组',
            value: 'yanfa2',
          }
        ]
      },
      {
        label: '外包部',
        value: 'waibao',
        children: [
          {
            label: '外包一组',
            value: 'waibao1',
          },
          {
            label: '外包二组',
            value: 'waibao2',
          }
        ]
      }
    ]
  },
  {
    elType: "el-date-picker",
    key: "createTime",
    type: 'date',
    valueFormat: 'yyyy-MM-dd',
    placeholder: "请选择截止时间"
  },
  {
    elType: "el-date-picker",
    key: "timeRange",
    type: 'daterange',
    span: 6,
    valueFormat: 'yyyy-MM-dd',
    rangeSeparator: '至',
    startPlaceholder: "开始日期",
    endPlaceholder: "结束日期"
  },
],
// 支持对搜索项下拉数据进行填充
this.$refs['searchCustom'].setFormItemOptions('sex', [
  {
    label: '男',
    value: 1
  },
  {
    label: '女',
    value: 2
  }]
)
// 搜索、重置方法
handleSearch (val) {
  console.log('val===>', val);
}
handleReset (val) {
  console.log('val===>', val);
}

组件源码

<template>
  <div class="search-wrapper">
    <el-form
      inline
      :model="formInfo"
      size="small"
    >
      <!-- 行列栅格布局 -->
      <el-row
        v-for="(formItem, index) in formItemList"
        :key="index"
        :gutter="20"
      >
        <el-col
          v-for="(item, itemIndex) in formItem"
          :key="itemIndex"
          :span="item.span"
        >
          <!-- 搜索项渲染 -->
          <el-form-item
            v-show="item.itemType == 'search'"
            :label="item.label"
          >
            <!-- 选择框单独处理,后续不能通过配置直接渲染的组件都需要单独处理 -->
            <el-select
              v-if="item.elType == 'el-select'"
              v-model="formInfo[item.key]"
              v-bind="{ ...item }"
              style="width: 100%"
            >
              <el-option
                v-for="option in item.options"
                :key="option.value"
                :label="option.label"
                :value="option.value"
              ></el-option>
            </el-select>
            <!-- 通用组件 -->
            <component
              v-else
              v-model="formInfo[item.key]"
              :is="item.elType"
              v-bind="{ ...item }"
              style="width: 100%"
            ></component>
          </el-form-item>
          <!-- 搜索栏按钮渲染 -->
          <el-form-item
            v-show="item.itemType == 'button'"
            style="text-align: right;"
          >
            <!-- 当搜索项数量超过一行时自动显示 折叠/展开按钮-->
            <el-button
              v-if="isCanFoldFlag"
              type="text"
              :icon="`el-icon-${toggleFoldFlag ? 'arrow-up' : 'arrow-down'}`"
              @click="handleToggleFold"
            >{{ toggleFoldFlag ? '展开' : '折叠' }}</el-button>
            <el-button
              type="primary"
              @click="handleSearch"
              icon="el-icon-search"
            >查询
            </el-button>
            <el-button
              type="info"
              @click="handleReset"
              icon="el-icon-refresh-right"
            >重置</el-button>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
  </div>
</template>
<script>
export default {
  name: 'SearchCustom',
  props: {
    itemList: {
      type: Array,
      required: true,
      default: () => []
    }
  },
  data () {
    return {
      toggleFoldFlag: false,  // 按钮状态:折叠/展开
      isCanFoldFlag: false,   // 是否展示按钮(折叠/展开)
      formInfo: {},  // 搜索栏搜索项值--用于表单绑定
      formItemList: []  // 搜索栏数据--用于渲染
    }
  },
  mounted () {
    // 初始化搜索栏表单默认值和渲染数据
    this.handleInitFormData()
  },
  methods: {
    /**
     * 设置搜索项Options数据
     * @param {*} field  搜索项名称
     * @param {*} options  选择数据
     */
    setFormItemOptions (field, options) {
      let itemIndex = this.itemList.findIndex(item => item.key == field)
      if (itemIndex != -1) {
        this.itemList[itemIndex].options = options
        // 设置完成后重新处理下数据 todo:可否简单化处理
        this.handleInitFormData()
      }
    },
    // 根据传入属性itemList对表单数据进行初始化
    handleInitFormData () {
      this.itemList.forEach(item => {
        item.itemType = 'search'
        /******************处理默认值***************/
        if (item.defaultValue != null) {
          this.$set(this.formInfo, item.key, item.defaultValue)
        }
      })
      // 初始化搜索栏数据渲染
      this.handleLayoutForm()
    },
    // 初始化搜索栏数据渲染
    handleLayoutForm () {
      // 初始化数据变量
      this.formItemList = []
      let spanTotal = 0
      let spanList = []
      /******************处理栅格布局渲染***************/
      this.itemList.forEach(item => {
        if (item.span == null) {
          // 默认占4格
          item.span = 4
        }
        /*
         * 累加span的值,如果大于24则表明需要填充下一行数据,否则填充当前行
         */
        spanTotal += item.span
        if (spanTotal > 24) {
          // 超过一行,可以展示按钮(折叠/展开)
          this.isCanFoldFlag = true
          this.formItemList.push(spanList)
          // 开启下一行的填充
          spanTotal = item.span
          spanList = [item]
        } else {
          spanList.push(item)
        }
      })
      // 当数据不够一行或为最后一行时候,在最后面追加按钮
      if (spanTotal <= 24) {
        // 剩余空间不足4(即空余一个搜索项)
        if (24 - spanTotal >= 4) {
          spanList.push({
            span: 24 - spanTotal,
            itemType: 'button'
          })
          this.formItemList.push(spanList)
        } else {
          // 超过一行,可以展示按钮(折叠/展开)
          this.isCanFoldFlag = true
          this.formItemList.push(spanList)
          this.formItemList.push([{ span: 24, itemType: 'button' }])
        }
        spanTotal = 0
        spanList = []
      }
    },
    // 控制按钮折叠/展开
    handleToggleFold () {
      this.toggleFoldFlag = !this.toggleFoldFlag
      // 处理折叠/展开对搜索项的影响
      if (this.toggleFoldFlag) {
        let spanTotal = 0
        let spanList = []
        // 获取足够展示一行的搜索项数据,后续拼接按钮展示
        for (let i = 0; i < this.itemList.length; i++) {
          let item = this.itemList[i]
          // 20 是因为按钮最少展示一个搜索项宽度:4
          if ((spanTotal + item.span) > 20) {
            break
          }
          spanTotal += item.span
          spanList.push(item)
        }
        spanList.push({ span: 24 - spanTotal, itemType: 'button' })
        this.formItemList = [spanList]
        console.log('this.formItemList===>', this.formItemList);

      } else {
        this.handleLayoutForm()
      }
    },
    /**
     * 搜索查询
     */
    handleSearch () {
      this.$emit('formSearch', this.formInfo)
    },
    /**
     * 搜索重置
     */
    handleReset () {
      this.formInfo = {}
      this.handleInitFormData()
      this.$emit('formReset', this.formInfo)
    }
  }
}
</script>
<style lang="scss" scoped>
.search-wrapper ::v-deep .el-form-item--small {
  width: 100%;
  display: flex;
  align-items: center;
}

.search-wrapper ::v-deep .el-form-item--small .el-form-item__content {
  flex: 1 0 auto;
}
</style>

组件说明

栅格布局分化

栅格布局是分行和列的,但传入的搜索项数据却是个数组。所以为了方便渲染,需要将其转化为二维数组。

但同时按钮是需要跟在搜索项后面的,在搜索项不满一行或者最后一行不满的情况下,且满足剩余空间大于等于一个搜索项(我这里看是三个按钮(查询、重置和 展开/折叠)占一个可以正常显示 ),按钮追加到搜索项所在行内,发反之,按钮独占一行。

主要代码在handleLayoutForm 和 handleToggleFold 两个方法中

填充搜索项数据

由于要进行栅格布局分化,所以填充完数据之后再次进行栅格布局处理。
我一直在思考这一步是否可以简化?个人有两点方向,但也觉得麻烦。如有更好的方式,欢迎讨论。

  • 目前这种方式,先填充,再处理栅格
  • 两次查找,准备定位,填充数据
 /**
     * 设置搜索项Options数据
     * @param {*} field  搜索项名称
     * @param {*} options  选择数据
     */
    setFormItemOptions (field, options) {
      let itemIndex = this.itemList.findIndex(item => item.key == field)
      if (itemIndex != -1) {
        this.itemList[itemIndex].options = options
        // 设置完成后重新处理下数据 todo:可否简单化处理
        this.handleInitFormData()
      }
    },

搜索项样式穿透

这里处理的原因是栅格布局下el-form-item内的组件并没有占满空间,所以强行调整了一波。

<style lang="scss" scoped>
.search-wrapper ::v-deep .el-form-item--small {
  width: 100%;
  display: flex;
  align-items: center;
}

.search-wrapper ::v-deep .el-form-item--small .el-form-item__content {
  flex: 1 0 auto;
}
</style>

组件渲染

component动态组件的渲染,重点要说的是 v-bind=“{…item}” 。我最开始想到的是通过 a t t r s / attrs/ attrs/listener组合来做的,但是$attrs接收到的是除了props之外的挂载到子组件根标签上的属性,似乎也不太合适。最后无意中写出了这个组合,渲染出来了,但具体什么原理,一时半会儿还说不上来,有明白人可以在评论区说一下嘛

<!-- 选择框单独处理,后续不能通过配置直接渲染的组件都需要单独处理 -->
<el-select
  v-if="item.elType == 'el-select'"
  v-model="formInfo[item.key]"
  v-bind="{ ...item }"
  style="width: 100%"
>
  <el-option
    v-for="option in item.options"
    :key="option.value"
    :label="option.label"
    :value="option.value"
  ></el-option>
</el-select>
<!-- 通用组件 -->
<component
  v-else
  v-model="formInfo[item.key]"
  :is="item.elType"
  v-bind="{ ...item }"
  style="width: 100%"
></component>

个人说

这一版的内容也是经过之前提到的项目代码在真实项目中实践之后自己总结出来的,原项目也很好,但是总觉得封装程度有点深(可能是我能力不够哈,原项目很牛逼!!!),所以选择了搜索栏一部分来实现,配合之前的搜索栏容器处理,虽然没有经过真实项目使用实践 ,但是我个人觉得很满意。

容器部分选择使用了栅格布局,这样就更好控制排版统一。

表单组件部分采用了组件动态渲染,一些特殊的组件通过组件名称自行渲染(如,因为下拉数据没法通过配置渲染)。

最开始想做这个组件时候,觉得最重要的点就是如何通过配置属性转换为对应的组件,其他的属性到时再想办法解决。天知道当时脑子怎么了,我首先想到的居然是createElement方法。。。看了半天才转过来脑子:这玩意儿是从0到1创建东西的,不是用来从一到1做转换的。后来想到了component动态组件,但脑子可能还有点糊涂,想着只有Inpu输入框可以这么搞,还是不行,就用笨方法:v-if/v-else-if把对应组件进行了列举。结果吧,搞着搞着发现,除了select,其余除了组件名称不一样其余都一样,还是换回component组件吧,所以就成了现在这样。

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

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

相关文章

Aloudata AIR :国内首个 Data Fabric 逻辑数据平台

AIR 的寓意是“极致轻盈的数据交付”&#xff1a;A - Adaptive 自适应&#xff0c;I - Integration 集成&#xff0c;R - Resilience 弹性 News&#xff1a;Aloudata AIR 发布 作为国内首个 Data Fabric 逻辑数据平台&#xff0c;Aloudata AIR 通过自研的数据虚拟化技术&#…

使用树莓派学习——Linux库编程

树莓派开发——Linux静态动态库 文章目录 树莓派开发——Linux静态动态库一、分文件编程1.1 分文件编程的优点&#xff1a;1.2 分文件编程的步骤&#xff1a; 二、Linux的库2.1 函数库的概念&#xff1a;2.2 静态库和动态库的比较&#xff1a;静态数据库&#xff08;libXXX.a&a…

奖项再+1!通义灵码智能编码助手通过可信 AI 智能编码工具评估,获当前最高等级

阿里云的通义灵码智能编码助手参与中国信通院组织的可信AI智能编码工具首轮评估&#xff0c;最终获得 4 级评级&#xff0c;成为国内首批通过该项评估并获得当前最高评级的企业之一。 此次评估以《智能化软件工程技术和应用要求 第 2 部分&#xff1a;智能开发能力》为依据&…

C/C++的自由落体运动

目录 1. 前言 2. 正文 2.1 问题 2.2 解决办法 2.2.1 思路 2.2.2 代码实现 2.2.3 测试结果 3. 备注 1. 前言 这个题目非常有意思&#xff0c;可以活跃自己的思维&#xff0c;毕竟代码来源于生活&#xff0c;又返回给生活。 2. 正文 2.1 问题 题目描述&#xff1a; …

携手共建云安全未来 |“集美大学服云实习基地”授牌仪式圆满举行

集美大学服云实习基地授牌仪式 9月3日&#xff0c;集美大学服云实习基地授牌仪式在厦门成功举行。集美大学科研处副处长茅剑、计算机工程学院副院长刘晋明&#xff0c;以及安全狗副总裁&CTO陈荣有、副总裁刘春辉共同出席此次的授牌仪式。 01 会上&#xff0c;安全狗副总裁刘…

梨花声音教育退费普通话学习技巧之了解文化背景

在学习普通话的过程中&#xff0c;了解中国的文化背景是不可或缺的一环。语言不仅是交流的工具&#xff0c;更是文化的载体。通过深入了解中国的历史、文化和社会背景&#xff0c;学习者可以更好地理解和掌握普通话&#xff0c;使语言学习变得更加生动有趣。本文将从几个方面详…

监控平台总结之面试常问答案

思路 延伸的面试题总结及答案&#xff1a; 1.说说前端监控平台/监控SDK架构设计和难点亮点&#xff1f; 架构设计 数据采集层: SDK: 在前端集成的 SDK 负责采集数据&#xff0c;包括性能指标、用户行为、错误日志等。 数据收集: 实现高效的数据采集机制&#xff0c;支持实时…

C++_多态详解

多态的概念 概念&#xff1a;需要去完成某个行为时&#xff0c;当 不同的对象去完成 会产生出不同的状态。通俗点说就是 不同类型的对象去做同一个行为&#xff0c;产生的结果不同。 多态的定义及实现 虚函数 定义&#xff1a;即被virtual修饰的类成员函数称为虚函数 虚函…

多门店管理下的高效IT运维策略与实战指南

连锁门店作为直接面向消费者的服务点&#xff0c;是企业与顾客建立联系的关键触点。随着商业竞争的加剧&#xff0c;连锁门店企业纷纷通过扩大实体店面的规模来抢占市场份额。随着门店数量的激增&#xff0c;门店IT运维管理的复杂性和挑战也日益凸显。本文将深入剖析门店IT运维…

828华为云征文|采用Flexus云服务器X实例部署RTSP直播服务器

一、前言 这篇文章讲解&#xff1a; 采用华为云最新推出的Flexus云服务器X实例搭建RTSP服务器&#xff0c;完成视频直播需求。 随着实时视频流传输需求的增长&#xff0c;RTSP&#xff08;实时流协议&#xff09;服务器成为了许多视频监控、直播和多媒体应用的核心组件。在当…

有趣的手机端见缝插针游戏源码

有趣的手机端见缝插针游戏源码下载&#xff0c;注&#xff1a;本地预览请用火狐浏览器模拟移动端&#xff0c;chrome本地预览存在跨域问题。 微信扫码获取源码

vue3 响应式 API:shallowRef()和shallowReactive()

shallowRef() shallowRef()是一个用于创建浅层响应式引用的函数。它创建一个响应式数据&#xff0c;但只对顶层属性进行响应式处理。 特点&#xff1a; 只跟踪引用值的变化&#xff0c;不关心值内部的属性变化。 <template><div>{{ shallowRefObj }}</div>…

LLM 模型压缩之三: FoldGPT

0. 资源链接 论文: FoldGPT: Simple and Effective Large Language Model Compression Scheme 项目: to be released. 1. 背景动机 现有的大语言模型推理存在以下问题&#xff1a; LLM 模型因为有大量的参数&#xff0c;以及 next token 的预测方式&#xff0c;导致 LLM 模…

关于vue项目启动报错Error: error:0308010C:digital envelope routines::unsupported

周五啦&#xff0c;总结一下这周遇到的个别问题吧&#xff0c;就是关于启动项目的时候其他的东西都准备好了&#xff0c;执行命令后报错Error: error:0308010C:digital envelope routines::unsupported 这里看一下我标注的地方&#xff0c;然后总结一下就不难发现问题所在 查看…

OBS怎么设置录制配置?3个电脑录屏小技巧妥妥教会你

OBS Studio是一款广受好评的开源录屏和直播软件&#xff0c;它以其强大的功能和用户友好的操作界面而闻名。对于初次接触OBS的用户来说&#xff0c;可能会对软件的众多按钮感到困惑。本文将为你提供一份简洁明了的OBS录屏指南&#xff0c;帮助你快速上手。 演示机型&#xff1a…

下载量10w+!LLM经典《大型语言模型:语言理解和生成》pdf分享

介绍 近年来&#xff0c;人工智能在新语言能力方面取得了显著进展&#xff0c;深度学习技术的快速发展推动了语言AI系统在文本编写和理解方面的表现。这一趋势催生了许多新功能、产品和整个行业的兴起。 本书旨在为Python开发者提供实用工具和概念&#xff0c;帮助他们利用预…

IP地址与MAC地址的区别:‌理解网络层与数据链路层的基石

在网络通信的广阔天地中&#xff0c;‌IP地址与MAC地址如同两座灯塔&#xff0c;‌各自照亮着不同的海域。‌它们虽然都扮演着标识网络设备的重要角色&#xff0c;‌但却在网络的不同层次上发挥着作用。‌本文将带您走进IP地址与MAC地址的世界&#xff0c;‌简述MAC与IP地址的区…

在SOLIDWORKS中高效转换:从实体模型到钣金件的设计优化

在设计生产中&#xff0c;当我们收到中间格式的模型文件时&#xff0c;并希望将其转换为钣金件以进一步加工生产&#xff0c;该怎么做呢&#xff1f; 利用SOLIDWORKS软件&#xff0c;可以直接将实体模型转换为钣金件&#xff0c;来完成后续的设计。 中性文件 钣金件 一、设置…

万象奥科参展“2024 STM32全国巡回研讨会”—深圳站、广州站

9月3日-9月5日&#xff0c;万象奥科参展“2024 STM32全国巡回研讨会”— 深圳站、广州站。此次STM32研讨会将会走进全国11个城市&#xff0c;展示STM32在智能工业、无线连接、边缘人工智能、安全、图形用户界面等领域的产品解决方案及多样化应用实例&#xff0c;深入解读最新的…

谷歌seo文章如何优化效果更好?

优化文章效果其实就是让它更吸引人&#xff0c;让读者有兴趣读下去&#xff0c;同时也要让搜索引擎喜欢&#xff0c;写作风格要亲切自然&#xff0c;用聊天的方式跟读者沟通&#xff0c;别让他们觉得在读一篇枯燥的报告&#xff0c;原创内容是关键&#xff0c;我们需要提供独特…