vue3中,封装el-select选择器组件(一)——表单四等分布局、查询、重置resetFields、el-date-picker起止日期、特殊字符校验、自定义指令v-throttle用于按钮防抖

vue3中,封装el-select选择器组件(一)——表单四等分布局、查询、重置resetFields、el-date-picker起止日期、特殊字符校验、自定义指令v-throttle用于按钮防抖

效果

在这里插入图片描述
1-流程状态
在这里插入图片描述
2-牵头单位
在这里插入图片描述
3-系统内单位角色
在这里插入图片描述

页面文件

index.vue

<template>
  <div class="main-content">
    <el-form
      ref="formRef"
      class="inline-form"
      label-position="right"
      label-width="130px"
      :model="formInline"
    >
      <el-form-item class="width25" label="项目名称:" prop="prjName">
        <el-input
          v-model="formInline.prjName"
          maxlength="100"
          placeholder="请输入"
          @input="(e) => (formInline.prjName = replaceCommonText(e))"
        />
      </el-form-item>

      <el-form-item class="width25" label="开始时间:">
        <el-date-picker
          v-model="prjDate"
          end-placeholder="结束日期"
          format="YYYY-MM-DD"
          placeholder="请选择"
          range-separator="至"
          start-placeholder="开始日期"
          type="daterange"
          value-format="YYYY-MM-DD"
        />
      </el-form-item>
      <el-form-item class="width25" label="牵头单位:" prop="leadUnit">
        <unitSelect
          v-model="formInline.leadUnit"
          v-model:contrUnitName="formInline.leadUnitName"
          @change-unit="handleUnitChange"
        />
      </el-form-item>
      <el-form-item class="width25" label="系统内单位角色:" prop="innerRole">
        <dictSelect v-model="formInline.innerRole" :dictid="'sgCompRole'" />
      </el-form-item>

      <el-form-item class="width25" label="流程状态:" prop="processState">
        <dictSelect
          v-model="formInline.processState"
          :dictid="'projectExamine'"
        />
      </el-form-item>
      <el-form-item class="search_btn">
        <el-button
          v-throttle="3000"
          type="primary"
          @click="onSubmit(formInline)"
        >
          查询
        </el-button>
        <el-button
          v-throttle="3000"
          plain
          type="primary"
          @click="resetForm(formRef)"
        >
          重置
        </el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
<script setup>
  import { queryByPage } from "@/api/project/couny";
  import unitSelect from "@src/components/unitSelect";
  import dictSelect from "@src/components/dictSelect";
  import { replaceCommonText } from "@src/utils/validate";
  const formRef = ref();
  const prjDate = ref([]);
  const formInline = ref({
    prjName: "",
    startDate: "", //项目开始日期
    endDate: "", //项目结束日期
    leadUnitName: "", //牵头单位
    innerRole: "", //系统内单位角色
    processState: "", //流程状态
  });
  const page = reactive({
    pageSize: 10,
    pageNumber: 1,
    total: 0,
  });

  //重置-写法一
  const resetForm = (formEl) => {
    if (!formEl) return;
    prjDate.value = [];
    formEl.resetFields();
    formInline.leadUnit = "";
    onLoad();
  };
  //重置-写法二
  // const resetForm = () => {
  //   formRef.value.resetFields()
  //   onLoad()
  // }
  //重置-写法三
  // const resetForm = (formEl: FormInstance | undefined) => {
  //   if (!formEl) return
  //   formEl.resetFields()
  //   onLoad()
  // }

  //查询
  const onSubmit = () => {
    onLoad();
  };
  const onLoad = async () => {
    const formData = {
      pageSize: page.pageSize,
      pageNumber: page.pageNumber,
      ...formInline,
      startDate: prjDate.value ? prjDate.value[0] : "",
      endDate: prjDate.value ? prjDate.value[1] : "",
    };
    await queryByPage(formData).then((res) => {
      tableData.value = res.data.data;
      page.pageSize = res.data.pageSize;
      page.total = Number(res.data.total);
      page.pageNumber = res.data.pageNumber;
    });
  };
  const handleUnitChange = (val) => {
    formInline.leadUnit = val.id;
    formInline.leadUnitName = val.orgObjMdmName;
  };
</script>
<style lang="scss" scoped></style>
公共样式

src\assets\css\element.css

.main-content {
  padding: 20px 30px;
}
.inline-form {
  overflow: hidden;
  /* border-bottom: 1px dashed #ccc; */
}
.inline-form .search_btn{
  float: right;
  margin-right: 0 !important;
}
引用方法

src\app\science\api\project\couny.js

import request from '@src/utils/request'
import { sciencePostUrl } from '@/config'

//立项管理项目分页列表查询
export const queryByPage = (data) => {
  return request({
    url: `${sciencePostUrl}/prj/queryByPage`,
    method: 'post',
    data,
  })
}

src\utils\validate.ts

//  禁止输入框特殊字符校验 
export function replaceCommonText(e: any) {

  if (!checkSpecificKeyWord(e)) {
    // 提交关键字
    ElMessage({
      message: '不能包含关键词: ' + wordKey,
      type: 'warning',
    })
    const y = e.replace(wordKey, '')
    return y
  } else {
    const str = e.replace(
      /[`~!@#$%^&*()_\-+=<>?:"{}|,./;'\\[\]·~!@#¥%……&*()——\-+={}|《》?:“”【 】、;,’。 ]/g,
      ''
    )

    const y = str.replace(/\s+/g, '')
    return y
  }
}
//  禁止输入框特殊字符校验-简约版
export function replaceSimpleText(e: any) {

  if (!checkSpecificKeyWord(e)) {
    // 提交关键字
    ElMessage({
      message: '不能包含关键词: ' + wordKey,
      type: 'warning',
    })
    const y = e.replace(wordKey, '')
    return y
  } else {
    const str = e.replace(
      /[`~!@#$%^&*_\+=<>?:"{}|;'\\[\]·~!@#¥%……&*——\+={}|?:“”【 】;’。 ]/g,
      ''
    )

    const y = str.replace(/\s+/g, '')
    return y
  }
}
/**
 * @description form表单特定字符校验
 * @param value
 * @returns {boolean}
 */
export function validateCommonText(rule: any, value: any, callback: any) {
    const err: any = validatorSpecialCharacter(value)
    if (err) {
      callback(new Error(err.message))
      return
    }
  callback()
}
// export function validateCommonText(rule: any, value: any, callback: any) {
  // const noChars = "[`~!#$^&*\"()=|{}'‘: ; ',\\[\\].<>/?~!#¥……&*()——|{}【】‘;:”“'。,、?]‘'@ /% ‘"
  // const v = value || ''

  // for (let i = 0; i < noChars.length; i++) {
  //   const char = noChars[i]
  //   if (v.indexOf(char) != -1) {
  //     callback(new Error('不能使用特殊字符'))
  //     return
  //   }
  // }
  // const words = ['javascript', 'script', 'function', 'jscript', 'vbscript', 'confirm', 'onfocus', 'onblur', 'alert', 'location', 'document', 'window', 'onclick', 'href', 'prompt', 'onerror', '/*', 'data:', '\\u003e', '\\u003c', 'eval', 'url', 'expr', 'URLUnencoded', 'referrer', 'write', 'writeIn', 'body.innerHtml', 'execScript', 'setInterval', 'setTimeout', 'open', 'navigate', 'srcdoc', 'iframe', 'body', 'form', 'base', 'img', 'src', 'style', 'div', 'object', 'meta', 'link', 'input', 'comment', 'br', 'and', 'or', 'exec', 'insert', 'select', 'delete', 'update', 'alter', 'create', 'drop', 'count', 'chr', 'char', 'asc', 'mid', 'substring', 'master', 'truncate', 'declare', 'restore', 'backup', 'like', 'table', 'from', 'grant', 'use', 'column_name', 'group_concat', 'information_schema.columns', 'union', 'where', 'order', 'by', 'join', 'modify', 'into', 'substr', 'ascii', 'having']
  // for (let i = 0; i < noChars.length; i++) {
  //   const word = words[i]
  //   if (v.indexOf(word) != -1) {
  //     callback(new Error('不能包含: ' + word))
  //     return
  //   }
  // }
  // callback()
// }
自定义指令

library\plugins\directive.ts

import type { DirectiveBinding } from 'vue'

export function setup(app: any) {
  /**
   * @description 自定义指令v-throttle
   */
  app.directive('throttle', {
    mounted(el: any, binding: DirectiveBinding) {
      let { throttleTime } = binding.value
      if (!throttleTime) {
        throttleTime = 1000
      }
      let timer: any
      let disable = false
      el.addEventListener(
        'click',
        (event: any) => {
          if (timer) {
            clearTimeout(timer)
          }
          if (!disable) {
            disable = true
          } else {
            event && event.stopImmediatePropagation()
          }
          timer = setTimeout(() => {
            timer = null
            disable = false
          }, throttleTime)
        },
        true
      )
    },
  })
}