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
      )
    },
  })
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3 组件封装相比 Vue2 有了很大的改进,可以使用 Composition API 来进行组件的编写,下面是一个使用 Vue3 Composition API 封装的带有搜索功能的 el-select 组件的示例: ```vue <template> <el-select v-model="selectedValue" filterable remote :remote-method="search" :loading="isLoading" :loading-text="loadingText" :no-match-text="noMatchText" :popper-append-to-body="false" :popover-class="popoverClass" :debounce="debounce" :placeholder="placeholder" :clearable="clearable" :disabled="disabled" > <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </template> <script> import { reactive, toRefs } from 'vue' export default { name: 'ElSelectSearch', props: { // 下拉选项列表,格式为 [{ label: '选项1', value: 'value1' }, ...] options: { type: Array, default: () => [] }, // 是否可清空 clearable: { type: Boolean, default: false }, // 是否禁用 disabled: { type: Boolean, default: false }, // 是否显示搜索框 filterable: { type: Boolean, default: true }, // 下拉框的 class popoverClass: { type: String, default: '' }, // 搜索框 placeholder placeholder: { type: String, default: '请输入搜索内容' }, // 输入搜索内容后,触发搜索的延迟时间 debounce: { type: Number, default: 300 }, // 搜索的 loading 文本 loadingText: { type: String, default: '加载...' }, // 没有匹配项的文本 noMatchText: { type: String, default: '没有匹配的数据' }, // 是否正在加载 isLoading: { type: Boolean, default: false } }, setup(props, { emit }) { const state = reactive({ selectedValue: '', searchValue: '', searchTimer: null }) // 监听选的值变化 const handleSelectChange = (value) => { state.selectedValue = value emit('change', value) } // 监听搜索框输入的值变化 const handleSearchValueChange = (value) => { state.searchValue = value if (state.searchTimer) { clearTimeout(state.searchTimer) } state.searchTimer = setTimeout(() => { emit('search', value) }, props.debounce) } // 执行搜索的方法 const search = (query) => { emit('search', query) } // 将响应式数据转化为 ref const refs = toRefs(state) return { ...refs, handleSelectChange, handleSearchValueChange, search } } } </script> ``` 这里我们使用了 `reactive` 和 `toRefs` 来创建响应式数据,并将其转化为 ref,方便在模板使用。同时,我们也使用了 Vue3 的两个新的钩子函数 `setup` 和 `emit`。其,`setup` 钩子函数用来替代 Vue2 的 `beforeCreate` 和 `created` 钩子函数,用于组件的初始化和响应式数据的创建。`emit` 函数用于向父组件派发事件。在 `setup` 函数,我们将响应式数据和方法都返回给模板使用。 该组件支持以下 props: - `options`:下拉选项列表,格式为 `[{ label: '选项1', value: 'value1' }, ...]`。 - `clearable`:是否可清空。 - `disabled`:是否禁用。 - `filterable`:是否显示搜索框。 - `popoverClass`:下拉框的 class。 - `placeholder`:搜索框 placeholder。 - `debounce`:输入搜索内容后,触发搜索的延迟时间。 - `loadingText`:搜索的 loading 文本。 - `noMatchText`:没有匹配项的文本。 - `isLoading`:是否正在加载。 该组件支持以下事件: - `change`:选的值变化时触发。 - `search`:搜索框输入内容变化或者点击下拉框时触发。 该组件的搜索功能使用了 ElementUI 的远程搜索,可以在 `search` 方法进行异步搜索。需要注意的是,在使用远程搜索时,需要设置 `remote` 和 `:remote-method` 属性。`remote` 表示是否使用远程搜索,`:remote-method` 表示远程搜索的方法。 同时,我们也使用了 ElementUI 的 `el-option` 组件来显示下拉选项列表,使用 `v-for` 来遍历 `options` 数组的每一个元素,并将其显示在下拉选项列表。`el-select` 组件的 `v-model` 双向绑定 `selectedValue` 变量,当选的值发生变化时,会触发 `handleSelectChange` 方法。 最后,我们将响应式数据和方法都返回给模板使用,模板可以直接使用它们来进行渲染和交互。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值