温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么基于element-ui封装查询组件

发布时间:2021-10-18 09:20:05 来源:亿速云 阅读:274 作者:小新 栏目:开发技术

这篇文章将为大家详细讲解有关怎么基于element-ui封装查询组件,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

功能

接着前一篇文章基于element-ui框架封装一个更好用的表格组件,我们开始写查询组件. 查询组件的话,需要有什么呢? 下面我画了一个粗略的原型,基本描述了查询组件需要实现的功能了。

怎么基于element-ui封装查询组件

基本的查询功能 [输入条件,选择下拉数据点击查询]

添加查询下拉面板 [很多查询的话,一行放不下,需要给一下更多查询下拉面板,除掉默认查询的条件,都放下拉面板去,具体默认查询条件放几个,可以做成通过传入的参数控制]

添加条件展示 [如果有更多查询面板的话,不打开查询面板,根本不清楚数据是根据哪些条件查出来的.]

添加功能按钮区 [一般放置增删改等批量操作的功能按钮]

基本的查询功能

查询功能的话,需要搭配element-ui的输入框、下拉框、日期框等组件去实现,而用我们的组件的话,希望用一个数组去描述这个查询条件,然后组件根据数组去把条件给识别并渲染出来. 首先,我们得先定义一下这个数组到底长什么样.

// methods initSearch () {   const searchArr = this.searchArr   if (searchArr && searchArr.length) {     let searchForm = {}     searchArr.forEach((val) => {       searchForm[val.key] = ''     })     this.searchForm = searchForm   } } // mounted mounted () {     this.initSearch() },

目前最基本的就是这三个字段了,字段意义在代码注释已经写明白了。 后边这个对象里边可能还会扩展一些其他的字段. 比如下拉数据, 它一般都是通过后台接口给到前端, 我们可以在这里添加一个url、param、method来去定义接口的名称、参数和请求方式. 当然后面实现的时候,我们再说. 那么我们开始开发吧.

查询条件初始化

外部我们传入了searchArr数据后,我们得先在mounted的时候,遍历它,给内容定义的查询条件searchForm设置响应式数据.

// methods initSearch () {   const searchArr = this.searchArr   if (searchArr && searchArr.length) {     let searchForm = {}     searchArr.forEach((val) => {       searchForm[val.key] = ''     })     this.searchForm = searchForm   } } // mounted mounted () {     this.initSearch() },

渲染页面

因为我们设计的查询页面是两部分的,包括展示在外边的查询条件和展示在更多的查询条件. 这样的话,如果我们在template里边把结构定义好的话,会发现,两遍需要写重复的代码。 如果后边扩展新功能上去的话,又是一个不好受的体力活了. 所以我们这边就在render函数里边写jsx,这样可以让结构更灵活,代码可以更好的复用. 思路说完了,那么开始写代码了

// props 传入一个searchArr数组描述查询条件都有哪一些 /**  * 查询条件描述  */ searchArr: {   type: Array,   default: () => [] }, // data 定义两个变量,searchForm:传递到后台的查询字段,selectOption:下拉数据 searchForm: {}, selectOption: {} // mounted 初始化数据 initSearch () {   const searchArr = this.searchArr   if (searchArr && searchArr.length) {     let searchForm = {}     searchArr.forEach((val) => {       searchForm[val.__key] = '' // 把用户定义的字段拿出来,放到searchForm里边,再赋值一个空字符串       this.setOption(val) // 如果是下拉数据的话,去把下拉的列表赋值一下放到selectOption里边     })     this.searchForm = searchForm   } }, // methods 设置下拉数据 async setOption (val) {   if (~['select', 'mulSelect'].indexOf(val.__type)) {     // 第一种情况如果下拉数据是本地写死的     if (val.data && Array.isArray(val.data)) {       this.$set(this.selectOption, val.__key, val.data)     } else if (val.fetchUrl) {       // 第二种情况,如果下拉数据是从后台接口传递过来的数据       const result = await request({         url: val.fetchUrl,         method: val.method || 'post'       })       if (result && result.data && result.data.success) {         this.$set(this.selectOption, val.__key, result.data.list || [])       }     }   } },

好的,我们完成初始化工作后,就可以在进行渲染工作了,前面我们说到,我们采用render函数里边写jsx会更灵活一点,那么我们开始写这部分的工作吧.

// render 函数 <div class="searchTable">     <el-form       inline={true}       props={{model: this.searchForm}}       ref="searchForm"       class="searchForm">       {          searchArr.map((o) => {           return components[o.__type] ? components[o.__type](h, o, this) : ''         })       }       <el-form-item>         <el-button size="small" type="primary" icon="el-icon-search" on-click={ queryTable }>查询</el-button>         <el-form-item>           <el-link                           type="primary"              underline={ false }              on-click={ () => { this.moreShow = !this.moreShow } }>更多查询           </el-link>         </el-form-item>       </el-form-item>       <div class="more-search animated"             class={ this.moreShow ? 'fadeInDown' : 'fadeOutUp' }             v-show={ this.moreShow }>            // ...更多查询       </div>     </el-form> </div>

在jsx中操作有个地方值得注意一下,在最新的vue-cli中,是已经支持了在jsx中使用v-model等指令,但是element-ui中的el-input使用会报错,下方使用的v-show指令就可以用的. 但是其实v-model也只是一个语法糖而已,我们这里就使用input事件拿到最新的输入数据,然后再赋值给searchForm. 这段代码是抽离出来了的,因为外部显示的查询条件和收缩的查询条件都得用到它,抽离出来后,就不用写重复的逻辑了。 以下是抽离的components组件

  /**    * 输入框 为什么抽离? 这里我们只是做表格查询需要。     * 其实如果要封装弹窗框那种表单提交组件。 也可以复用这里的逻辑    * @param { Function } h vue提供的h函数    * @param { Object } item 用户写入的描述对象    * @param { Object } vm vue实例    */   export const input = function (h, item, vm) {     const { searchForm } = vm     return (       <el-form-item label={item.label}>         <el-input           size="small"           on-input={(v) => { searchForm[item.__key] = v }}           props={{             value: searchForm[item.__key],             placeholder: "输入内容信息",             ...item           }}         >         </el-input>       </el-form-item>     )   }   /**    *     * @param { Function } h vue提供的h函数    * @param { Object } item 用户写入的描述对象    * @param { Object } vm vue实例    */   export const select = function (h, item, vm) {     const {        searchForm = {},        selectOption = {},      } = vm     /**      * 监听下拉改变事件      * @param { String | Number | Boolean } value 选择下拉数据的值      * @param { Object } value       */     const selectChange = function (value, item) {        searchForm[item.__key] = value       vm.$emit('on-change', value)     }     return (       <el-form-item label={item.label}>         <el-select           props={{             value: searchForm[item.__key],             placeholder: "===请选择===",             filterable: true,             clearable: true,             ...item           }}           on-change={ (val) => { selectChange(val, item) } }           size="small">             {               selectOption[item.__key] && selectOption[item.__key].map((o) => {                 return (                   <el-option                      key={ o.value }                      label={ o.text }                      value={ o.value } >                   </el-option>                 )               })             }         </el-select>       </el-form-item>     )   }        /**    *     * 多选的下拉框,可以再单选基础上加上两个属性,写一个这个方法,用户可以稍微少些几个单词.    * @param { Function } h vue提供的h函数    * @param { Object } item 用户写入的描述对象    * @param { Object } vm vue实例    */   export const mulSelect = function (h, item, vm) {     item['multiple'] = true     item['collapse-tags'] = true     return select(h, item, vm)   }

以上其实就是把element的几个组件抽离成独立的方法,我们在外边组件使用的时候,就能直接根据用户传递的type,匹配到对应的组件渲染了。 并且后边要增加新的查询组件的话,只要在这里扩展就行,不用修改其他地方。 更容易维护。 另外我们在组件内部默认一些行为,比如默认下拉可以搜索,默认有清空按钮等,如果系统不需要的话,也可在searchArr去写上对应属性覆盖.

return components[o.__type] ? components[o.__type](h, o, this) : ''

基本的渲染就写好了, 然后我们在外边使用组件

searchArr: [     {       __type: 'input',       label: '姓名',       __key: 'name'     },     {       __type: 'select',       label: '性别',       __key: 'sex',       fetchUrl: '/getSelect',       method: 'post'       // data: [       //   { text: '男', value: '1' },       //   { text: '女', value: '0' },       // ]     }, ]

写上对应的mock数据

Mock.mock(/\/getSelect/, 'post', () => {   return {     status: 200,     success: true,     message: '获取成功',     list: [       {         text: '男人',         value: '1'       },       {         text: '女人',         value: '2'       }     ],     total: data.list.length   } })

怎么基于element-ui封装查询组件

ok, 以上就简单的把条件通过数组描述的方式渲染出来了。 接下来,我们得做更多查询面板的查询条件.

更多查询以及展示优化

外边展示的查询条件按用户给的数量展示多少个,更多查询也可按照用户给定的参数展示一行展示多少个

=============== props =============== /**  * 外部查询条件展示多少个  */ frontCount: {   type: Number,   default: 2 }, /**  * 更多查询条件展示多少个  */ backCount: {   type: Number,   default: 3 } =============== end props =============== =============== computed =============== // 显示在页面上的查询条件 frontSearchArr: function () {   return this.searchArr.slice(0, this.frontCount) }, // 显示在更多查询里边的条件 backSearchArr: function () {   return this.searchArr.slice(this.frontCount, this.searchArr.length) }, // 返回宽度 getSpan: function () {   const yu = this.backSearchArr.length % this.backCount // 余数   const duan = 24 / this.backCount // 每个条件的宽度   if (yu === 0) {     return 24   } else {     return 24 - duan   } } =============== end computed =============== ============== render ==============   <div     style={`width: ${this.backCount * 265 + 30}px`}     class={ this.moreShow ? `${className} fadeInDown` : `${className} fadeOutUp` }      v-show={ this.moreShow }>     <el-row>     {       backSearchArr.map((o) => {         return (           <el-col span={24 / this.backCount}>             { components[o.__type] ? components[o.__type](h, o, this) : '' }           </el-col>         )       })     }       <el-col class="searchBtn" span={ getSpan } >         <el-button size="small" type="primary" icon="el-icon-search" on-click={ queryTable }>查询</el-button>         <el-button size="small" type="default" icon="el-icon-upload2" on-click={ () => {  this.moreShow = !this.moreShow  } }>收缩</el-button>       </el-col>     </el-row>   </div> ============== end render ==============

在计算属性里边设置外部显示的数据和内部显示的数据。 把数据切割成两部分. 搜索组件固定长度265. 然后根据条件计算出来更多查询面板的宽度,再根据getSpan计算属性算每行数据给的span宽度是多少. 查询和收缩按钮根据查询条件的多少,去计算它放哪个位置。

怎么基于element-ui封装查询组件
怎么基于element-ui封装查询组件

经测试,效果基本上符合要求.

下拉组件联动查询

比如我们需要用我们的查询组件写三级联动的话,应该怎么实现呢?

选择省后,需要根据选择的省加载对应的市下拉数据

如果删除省后,需要把对应的省和市的下拉也清空掉

联动主要就是做好这两块功能。 一块是加载对应数据,一块清空对应数据. ok, 清楚需要做什么了,我们就开始着手怎么做吧.

{   __type: 'select',   __key: 'province',   __fetchUrl: '/getProvince',   __method: 'get',   __nextKey: 'city',   __nextFetch: '/getCity',   __nextParam: ['province'],   __nextMethod: 'get',   __emptyArr: ['city', 'district'],   label: '省',   labelWidth: '40px', }, {   __type: 'select',   __key: 'city',   __method: 'get',   __nextKey: 'district',   __nextFetch: '/getDistrict',   __nextParam: ['province', 'city'],   __nextMethod: 'get',   __emptyArr: ['district'],   label: '市',   labelWidth: '40px', }, {   __type: 'select',   __key: 'district',   label: '区',   labelWidth: '40px', }

其中获取省的数据,其实只要写__fetchUrl: '/getProvince'和__method: 'get'定义请求接口就可以拿到下拉数据了。 然后选择省下拉的时候,需要在change事件里边去根据选择的省请求数据. 这时候我们需要在数据里边定义一下change的时候,需要做的事情. 下面看一下代码:

__nextKey: 'city',                 // 给哪一个下拉数据赋值 __nextFetch: '/getCity',           // 赋值的请求接口 __nextParam: ['province'],         // 请求参数 __nextMethod: 'get',               // 请求方式 __emptyArr: ['city', 'district']   // 当修改了下拉数据的时候,需要清空哪些下拉类别的值 /**  * 监听下拉改变事件  * @param { String | Number | Boolean } value 选择下拉数据的值  * @param { Object } value   */ const selectChange = async function (value, item) {    searchForm[item.__key] = value   // 置空下拉列表和下拉数据   if (item && item.__emptyArr) {     for (let i = 0; i < item.__emptyArr.length; i++) {       let key = item.__emptyArr[i]       if (selectOption[key]) {         selectOption[key] = []       }       vm.$set(searchForm, key, '')     }   }   if (item && item.__nextFetch && item.__nextParam) {     let param = {}     for (let j = 0; j < item.__nextParam.length; j++) {       let value = searchForm[item.__nextParam[j]]       if (value) {         param[item.__nextParam[j]] = value       }     }     const res = await request({       url: item.__nextFetch,       method: item.__nextMethod || 'post'     }, param)     if (res) {       let { data } = res       if (data && data.success) {         vm.$set(selectOption, item.__nextKey, data.list)       }     }   }   vm.$emit('on-change', value) }

ok, 这样基本就完成了三级联动的功能了。 以下是效果图

怎么基于element-ui封装查询组件

组件扩展

组件扩展就很简单了,如果我们还缺少一些需要的组件,可以直接在components.js里边新增一个

/**  * 日期选择器   * @param {*} h   * @param {*} item   * @param {*} vm   */ export const date = function (h, item, vm) {   const { searchForm } = vm   return (     <el-form-item label={item.label} labelWidth={item.labelWidth}>         <el-date-picker         on-input={(v) => { searchForm[item.__key] = v }}         props={{           type: 'date',           size: 'small',           value: searchForm[item.__key],           placeholder: "选择日期",           ...item         }}       >       </el-date-picker>     </el-form-item>   ) } // searchArr使用的时候添加 {   __type: 'date',   __key: 'birthday',   label: '生日' }

其他地方都不用修改,就完成了一个新查询条件类型的添加了. 以下是效果

怎么基于element-ui封装查询组件

搜索条件展示

搜索条件功能比较简单,就是在用户点击搜索后,显示输入的条件. 我们把这个分离出来作为一个独立的小组件

<query-info ref="queryInfo" on-remove={this.removeTag} selectionOption={ this.selectOption }></query-info>

这个组件传入下拉数组过去,我们在设计的时候,有说过,他还可以点击叉删除条件,所以得抛出来一个remove自定义事件,然后删除掉条件后,我们把这个条件清空,然后调用查询方法. 查询的时候,再去把搜索条件传递给组件,让组件显示出来。 这里需要注意,我们不能直接把搜索条件通过props传入到组件里边,如果是这样传入的话,由于数据是响应式的,在你输入条件的时候,下方就会显示出来,这并不是我们想要的效果,我们想要的效果是在点击查询按钮的时候,展示正在查询的查询条件. 所以这里的话,我们就在查询按钮方法里边,直接去调用它内部的方法把条件传入过去,然后内部再利用JSON.parse(JSON.stringify(val))的方式,实现一个深拷贝,让数据和外部数据隔离开.

removeTag (name) {   this.searchForm[name] = ''   this.queryTable() } // 查询 queryTable () {   this.$refs.queryInfo && this.$refs.queryInfo.queryTable(this.searchForm)   this.moreShow = false   this.$emit('search', this.searchForm) }

组件的实现如下:

<template>   <div class="queryInfo">     <el-tag       v-for="tag in tags"       :key="tag"       closable              @close="close(tag)"       >       {{displayName(tag)}}     </el-tag>   </div> </template> <script> import { getTitle } from '@/utils/utils' export default {   props: {     // 下拉数据     selectionOption: {       type: Object,       default: () => []     }   },   data () {     return {       // 查询条件       searchForm: {}     }   },   computed: {     /// 计算出输入的条件的数组     tags: function () {       let tags = []       let keys = Object.keys(this.searchForm)       keys.forEach((key) => {         if (this.searchForm[key]) {           tags.push(key)         }       })       return tags     }   },   methods: {     // 点击关闭     close (tag) {       this.searchForm[tag] = ''       this.$emit('remove', tag)     },     // 外部调用的方法     queryTable (searchForm) {       this.searchForm = JSON.parse(JSON.stringify(searchForm))     },     // 显示名称, 如果是下拉数据,则去下拉数据里边匹配到名称显示出来     displayName(key) {       let value = this.searchForm[key]       if (this.selectionOption[key]) {         return getTitle(value, this.selectionOption[key])       } else {         return value       }     }   } } </script> <style scoped> .queryInfo {   margin-bottom: 10px; } </style>

实现的效果如下:

怎么基于element-ui封装查询组件

添加功能按钮区

这个目前就在searchTable组件用插槽的方式加入

<div class="right">   {this.$slots.rightButton} </div> // 使用 <search-table :searchArr="searchArr" @search="search">   <template v-slot:rightButton>     <el-button        size="small"        type="success"        @click="() => { MessageBox({ message: '开发中', type: 'warning' })}">       添加     </el-button>   </template>  </search-table>

效果:

怎么基于element-ui封装查询组件

关于“怎么基于element-ui封装查询组件”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI