欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue3+elementPlus二次封裝表單的實(shí)現(xiàn)代碼

 更新時(shí)間:2024年03月25日 08:39:29   作者:Vhen  
最近使用Vue3+ElementPlus開(kāi)發(fā)項(xiàng)目,從整體上構(gòu)思組件的封裝。能寫(xiě)成組件的內(nèi)容都進(jìn)行封裝,方便多個(gè)地方使用,這篇文章給大家介紹了vue3+elementPlus二次封裝表單的實(shí)現(xiàn),并通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下

功能

  • Input輸入框

  • autocomplete自動(dòng)補(bǔ)齊輸入框

  • radio 單選框

  • checkbox 復(fù)選框

  • date 日期選擇框

  • select 下拉框

  • 如需添加更多功能參考elementPlus或者根據(jù)業(yè)務(wù)需求自行自定義組件

效果圖

目錄結(jié)構(gòu)

input

<template>
  <el-input
    v-bind="$attrs"
    v-model="modelValue"
    w-full
    @blur="props.blur ? props.blur($event) : false"
    @focus="props.focus ? props.focus($event) : false"
    @change="props.change ? props.change($event) : false"
    @input="props.input ? props.input($event) : false"
    @clear="props.clear ? props.clear() : false"
  />
</template>
<script lang="ts" setup>
import { ref, watch } from "vue";
const emit = defineEmits(["update:modelValue"]);
const props = defineProps({
  modelValue: {
    type: String,
    default: () => "",
  },
  blur: {
    type: Function,
    default: () => () => {},
  },
  focus: {
    type: Function,
    default: () => () => {},
  },
  change: {
    type: Function,
    default: () => () => {},
  },
  input: {
    type: Function,
    default: () => () => {},
  },
  clear: {
    type: Function,
    default: () => () => {},
  },
});

const modelValue = ref(props.modelValue);
//監(jiān)聽(tīng)父組件的值
watch(
  () => props.modelValue,
  () => {
    modelValue.value = props.modelValue;
  },
);

// 通過(guò)emit將值傳遞給父組件
emit("update:modelValue", modelValue);
</script>
<style lang="scss" scoped></style>

select

<template>
  <el-select
    v-model="modelValue"
    v-bind="$attrs"
    w-full
    @change="props.change ? props.change($event) : false"
    @visible-change="props.visibleChange ? props.visibleChange($event) : false"
    @remove-tag="props.removeTag ? props.removeTag($event) : false"
    @clear="props.clear ? props.clear() : false"
    @blur="props.blur ? props.blur($event) : false"
    @focus="props.focus ? props.focus($event) : false"
  >
    <el-option
      v-for="item in options"
      :key="item[valueFiled]"
      :label="item[labelFiled]"
      :value="item[valueFiled]"
    ></el-option>
  </el-select>
</template>
<script lang="ts" setup>
import { ref, watch } from "vue";
const emit = defineEmits(["update:modelValue"]);
const props = defineProps({
  modelValue: {
    type: [String, Array],
    default: () => "",
  },
  options: {
    type: Array as any,
    default: () => [],
  },
  valueFiled: {
    type: String,
    default: "value",
  },
  labelFiled: {
    type: String,
    default: "label",
  },
  change: {
    type: Function,
    default: () => () => {},
  },
  visibleChange: {
    type: Function,
    default: () => () => {},
  },
  removeTag: {
    type: Function,
    default: () => () => {},
  },
  clear: {
    type: Function,
    default: () => () => {},
  },
  blur: {
    type: Function,
    default: () => () => {},
  },
  focus: {
    type: Function,
    default: () => () => {},
  },
});

const modelValue = ref(props.modelValue);

//監(jiān)聽(tīng)父組件的值
watch(
  () => props.modelValue,
  () => {
    modelValue.value = props.modelValue;
  },
);

// 通過(guò)emit將值傳遞給父組件
emit("update:modelValue", modelValue);
</script>
<style lang="scss" scoped></style>

autocomplete

<template>
  <el-autocomplete
    v-bind="$attrs"
    v-model="modelValue"
    style="width: 100%"
    @select="props.select ? props.select($event) : false"
    @change="props.change ? props.change($event) : false"
  />
</template>
<script lang="ts" setup>
import { ref, watch } from "vue";
const emit = defineEmits(["update:modelValue"]);
const props = defineProps({
  modelValue: {
    type: String,
    default: () => "",
  },
  select: {
    type: Function,
    default: () => () => {},
  },
  change: {
    type: Function,
    default: () => () => {},
  },
});

const modelValue = ref(props.modelValue);
//監(jiān)聽(tīng)父組件的值
watch(
  () => props.modelValue,
  () => {
    modelValue.value = props.modelValue;
  },
);

// 通過(guò)emit將值傳遞給父組件
emit("update:modelValue", modelValue);
</script>

date

<template>
  <el-date-picker
    v-model="Val"
    v-bind="$attrs"
    style="width: 100%"
    @change="props.change ? props.change($event) : false"
    @blur="props.blur ? props.blur($event) : false"
    @focus="props.focus ? props.focus($event) : false"
    @calendar-change="props.calendarChange ? props.calendarChange($event) : false"
    @panel-change="(a, b, c) => (props.panelChange ? props.panelChange(a, b, c) : false)"
    @visible-change="props.visibleChange ? props.visibleChange($event) : false"
  ></el-date-picker>
</template>

<script lang="ts" setup>
import { ref, watch } from "vue";
const emit = defineEmits(["update:modelValue"]);
const props = defineProps({
  modelValue: {
    type: [String, Array, Date],
    default: () => "",
  },
  change: {
    type: Function,
    default: () => () => {},
  },
  blur: {
    type: Function,
    default: () => () => {},
  },
  focus: {
    type: Function,
    default: () => () => {},
  },
  calendarChange: {
    type: Function,
    default: () => () => {},
  },
  panelChange: {
    type: Function,
    default: () => () => {},
  },
  visibleChange: {
    type: Function,
    default: () => () => {},
  },
});

const Val = ref(props.modelValue);
//監(jiān)聽(tīng)父組件的值
watch(
  () => props.modelValue,
  () => {
    Val.value = props.modelValue;
  },
);

// 通過(guò)emit將值傳遞給父組件
emit("update:modelValue", Val);
</script>

checkbox

<template>
  <el-checkbox-group
    v-model="Val"
    v-bind="$attrs"
    @change="props.change ? props.change($event) : false"
  >
    <template v-if="props.cType === 'button'">
      <el-checkbox-button
        v-for="item in options"
        :key="item[valueFiled]"
        :value="item[valueFiled]"
        >{{ item[labelFiled] }}</el-checkbox-button
      >
    </template>
    <template v-else>
      <el-checkbox
        v-for="item in options"
        :key="item[valueFiled]"
        :value="item[valueFiled]"
        :border="props.cType === 'border'"
        >{{ item[labelFiled] }}</el-checkbox
      >
    </template>
  </el-checkbox-group>
</template>
<script lang="ts" setup>
import { ref, watch } from "vue";
const emit = defineEmits(["update:modelValue"]);
const props = defineProps({
  modelValue: {
    type: Array,
    default: () => "",
  },
  options: {
    type: Array as any,
    default: () => [],
  },
  valueFiled: {
    type: String,
    default: "value",
  },
  labelFiled: {
    type: String,
    default: "label",
  },
  cType: {
    type: String,
    default: "",
  },
  change: {
    type: Function,
    default: () => () => {},
  },
});

const Val = ref(props.modelValue);
//監(jiān)聽(tīng)父組件的值
watch(
  () => props.modelValue,
  () => {
    Val.value = props.modelValue;
  },
);

// 通過(guò)emit將值傳遞給父組件
emit("update:modelValue", Val);
</script>


radio

<template>
  <el-radio-group
    v-model="modelValue"
    v-bind="$attrs"
    @change="props.change ? props.change($event) : false"
  >
    <template v-if="props.cType === 'button'">
      <el-radio-button v-for="item in options" :key="item[valueFiled]" :value="item[valueFiled]">{{
        item[labelFiled]
      }}</el-radio-button>
    </template>
    <template v-else>
      <el-radio
        v-for="item in options"
        :border="props.cType === 'border'"
        :key="item[valueFiled]"
        :value="item[valueFiled]"
        >{{ item[labelFiled] }}</el-radio
      >
    </template>
  </el-radio-group>
</template>
<script lang="ts" setup>
import { ref, watch } from "vue";
const emit = defineEmits(["update:modelValue"]);
const props = defineProps({
  modelValue: {
    type: [Number, String, Boolean],
    default: () => "",
  },
  options: {
    type: Array as any,
    default: () => [],
  },
  valueFiled: {
    type: String,
    default: "value",
  },
  labelFiled: {
    type: String,
    default: "label",
  },
  cType: {
    //radio類(lèi)型:button/border
    type: String,
    default: "",
  },
  change: {
    type: Function,
    default: () => () => {},
  },
});

const modelValue = ref(props.modelValue);
//監(jiān)聽(tīng)父組件的值
watch(
  () => props.modelValue,
  () => {
    modelValue.value = props.modelValue;
  },
);

// 通過(guò)emit將值傳遞給父組件
emit("update:modelValue", modelValue);
</script>

cascader

<template>
  <el-cascader
    v-bind="$attrs"
    v-model="modelValue"
    style="width: 100%"
    @change="props.change ? props.change($event) : false"
    @expand-change="props.expandChange ? props.expandChange($event) : false"
  />
</template>
<script lang="ts" setup>
import { ref, watch } from "vue";
const emit = defineEmits(["update:modelValue"]);
const props = defineProps({
  modelValue: {
    type: Array,
    default: () => [],
  },
  change: {
    type: Function,
    default: () => () => {},
  },
  expandChange: {
    type: Function,
    default: () => () => {},
  },
});

const modelValue = ref(props.modelValue);
//監(jiān)聽(tīng)父組件的值
watch(
  () => props.modelValue,
  () => {
    modelValue.value = props.modelValue;
  },
);

// 通過(guò)emit將值傳遞給父組件
emit("update:modelValue", modelValue);
</script>

types

/*
 * @Author: vhen
 * @Date: 2024-03-24 00:36:03
 * @LastEditTime: 2024-03-24 15:21:30
 * @Description: 現(xiàn)在的努力是為了小時(shí)候吹過(guò)的牛逼!
 * @FilePath: \vhen-vue3-admin-pro\src\components\SearchForm\types.ts
 * 
 */
export type FormType = "input" | "select" | "radio" | "cascader" | "autocomplete" | "date" | "daterange" | "checkbox";

export interface ItemOption {
  label: string
  value: string | number
  disabled?: boolean
}

export interface FormItemVO {
  type: FormType //輸入框類(lèi)型
  label: string //輸入框標(biāo)題
  disabled?: boolean//表單是否可修改 默認(rèn)false
  placeholder?: any //輸入框默認(rèn)顯示內(nèi)容
  prop: string //表單校驗(yàn)
  options?: ItemOption[] | (() => ItemOption[]) //選擇器的可選子選項(xiàng) select
  span?: number // 表單柵格數(shù)
  offset?: number // 表單柵格偏移
  clearable?: boolean // 是否可清空
  size?: string // 輸入框大小
  multiple?: boolean // 是否多選
  collapseTags?: boolean // 是否折疊
  collapseTagsThreshold?: number // 多選時(shí)標(biāo)簽的閾值,大于該閾值時(shí)折疊
  filterable?: boolean // 是否可搜索
  allowCreate?: boolean // 是否支持創(chuàng)建
  radioType?: string // 單選框類(lèi)型
}

export interface PropsVO {
  formData: object  // 表單數(shù)據(jù)
  formItem: FormItemVO[] // 表單配置項(xiàng)
  span?: number // 表單柵格數(shù)
  isSeniorSearch?: boolean // 是否高級(jí)搜索
  gutter?: number // 表單柵格間隔
  showButton?: boolean // 是否顯示查詢(xún)按鈕
}

index.vue

<template>
  <section class="search-form">
    <el-form :model="props.formData" v-bind="$attrs">
      <el-row :gutter="props.gutter">
        <el-col
          v-for="column in useFormItem"
          :key="column.prop"
          :span="column.span"
          :offset="column.offset"
        >
          <el-form-item :label="`${column.label}`" :prop="column.prop">
            <component
              :is="componentType[column.type]"
              v-bind="column"
              v-model="props.formData[column.prop]"
            />
          </el-form-item>
        </el-col>
        <template v-if="$slots.default">
          <slot />
        </template>
        <el-col :span="props.span" style="flex: 1; max-width: 100%" v-if="showButton">
          <div flex justify="end" items-center w-full h-full>
            <div
              v-if="isSeniorSearch"
              flex
              items-center
              mr-2
              class="senior-search"
              @click="isShow = !isShow"
              cursor="pointer"
            >
              <div class="text">{{ isShow ? "收起" : "展開(kāi)" }}</div>
              <div class="flex m-left-4">
                <el-icon>
                  <ArrowUp v-if="isShow" />
                  <ArrowDown v-else />
                </el-icon>
              </div>
            </div>
            <el-button @click="$emit('reset')" :icon="RefreshLeft">重置</el-button>
            <el-button type="primary" class="m-bottom-12" @click="$emit('search')" :icon="Search"
              >查詢(xún)</el-button
            >
          </div>
        </el-col>
      </el-row>
    </el-form>
  </section>
</template>
<script lang="ts" setup>
import { RefreshLeft, Search } from "@element-plus/icons-vue";
import { FormInstance } from "element-plus";
import { computed, markRaw, ref } from "vue";
import VhenAutocomplete from "./src/VhenAutocomplete.vue";
import VhenCascader from "./src/VhenCascader.vue";
import VhenCheckbox from "./src/VhenCheckbox.vue";
import VhenDatePicker from "./src/VhenDatePicker.vue";
import VhenInput from "./src/VhenInput.vue";
import VhenRadio from "./src/VhenRadio.vue";
import VhenSelect from "./src/VhenSelect.vue";
import { PropsVO } from "./types";

const emit = defineEmits<{
  (e: "reset"): void;
  (e: "search"): void;
}>();

const props = withDefaults(defineProps<PropsVO>(), {
  isSeniorSearch: false,
  gutter: 12,
  span: 8,
  showButton: true,
});
const isShow = ref(false);
const useFormItem = computed(() => {
  const isShowRow = props.isSeniorSearch && !isShow.value && props.showButton;
  if (isShowRow) {
    const num = Math.floor(24 / props.span) - 1;
    return props.formItem.slice(0, num);
  } else {
    return props.formItem;
  }
});

const componentType = markRaw({
  input: VhenInput,
  select: VhenSelect,
  radio: VhenRadio,
  cascader: VhenCascader,
  autocomplete: VhenAutocomplete,
  date: VhenDatePicker,
  daterange: VhenDatePicker,
  checkbox: VhenCheckbox,
});

const formRef = ref<FormInstance>();
defineExpose({ formRef });
</script>
<style lang="scss" scoped>
.senior-search {
  color: var(--el-text-color-regular);
  .text {
    font-size: 14px;
  }
}
</style>

組件案例

<template>
  <div>
    <SearchForm
      :formData="formData"
      :form-item="formItemList"
      :rules="formRules"
      :span="6"
      label-position="top"
      label-width="100px"
      isSeniorSearch
      @reset="resetData"
      @search="handleSearch"
    >
    </SearchForm>
    <pre>
    {{ formData }}
    </pre>
  </div>
</template>
<script lang="ts" setup>
import SearchForm from "@/components/SearchForm/index.vue";
import { FormRules } from "element-plus";
import { reactive } from "vue";
const formData = reactive({
  userName: "",
  email: "843348394@qq.com",
  sex: "1",
  area: [],
  city: "",
});
const formItemList = reactive([
  {
    type: "input",
    label: "姓名",
    prop: "userName",
    clearable: true,
    span: 6,
    placeholder: "請(qǐng)輸入姓名",
    // disabled: true,
    input: handleInput,
  },
  {
    type: "autocomplete",
    label: "郵箱",
    prop: "email",
    span: 6,
    "fetch-suggestions": querySearch,
  },
  {
    type: "daterange",
    label: "出生日期",
    prop: "birthday",
    span: 6,
  },
  {
    type: "radio",
    label: "-",
    prop: "sex",
    cType: "button",
    span: 6,
    options: [
      {
        value: "0",
        label: "男",
      },
      {
        value: "1",
        label: "女",
      },
    ],
  },
  {
    type: "checkbox",
    label: "工作地點(diǎn)",
    prop: "area",
    span: 6,
    options: [
      {
        label: "北京",
        value: "beijing",
      },
      {
        label: "上海",
        value: "shanghai",
      },
      {
        label: "深圳",
        value: "shenzhen",
      },
    ],
  },
  {
    type: "select",
    prop: "city",
    label: "城市",
    span: 6,
    options: [
      {
        label: "北京",
        value: "beijing",
      },
      {
        label: "上海",
        value: "shanghai",
      },
      {
        label: "深圳",
        value: "shenzhen",
      },
    ],
  },
]);

const resetData = () => {
  console.log(formData);
};
const handleSearch = () => {
  console.log(formData);
};

const formRules = reactive<FormRules>({
  userName: [{ required: true, message: "請(qǐng)輸入姓名", trigger: "blur" }],
  email: [{ required: true, message: "請(qǐng)輸入郵箱", trigger: "blur" }],
});
function handleInput(val: string | number) {
  console.log(val);
}
function querySearch(query: string, cb: any) {
  console.log(query);
  cb([query]);
}
</script>
<style lang="scss" scoped></style>

結(jié)束語(yǔ)

簡(jiǎn)單二次封裝form 表單組件,如大家有更好的方案,歡迎大家評(píng)論區(qū)討論,一起學(xué)習(xí)一起成長(zhǎng)....

以上就是vue3+elementPlus二次封裝表單的實(shí)現(xiàn)代碼的詳細(xì)內(nèi)容,更多關(guān)于vue3 elementPlus二次封裝表單的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • vue一步到位的實(shí)現(xiàn)動(dòng)態(tài)路由

    vue一步到位的實(shí)現(xiàn)動(dòng)態(tài)路由

    這篇文章主要介紹了vue一步到位的實(shí)現(xiàn)動(dòng)態(tài)路由,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • vue?iview封裝模態(tài)框的方法

    vue?iview封裝模態(tài)框的方法

    這篇文章主要為大家詳細(xì)介紹了vue?iview封裝模態(tài)框的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • 解決IOS端微信H5頁(yè)面軟鍵盤(pán)彈起后頁(yè)面下方留白的問(wèn)題

    解決IOS端微信H5頁(yè)面軟鍵盤(pán)彈起后頁(yè)面下方留白的問(wèn)題

    微信H5項(xiàng)目,ios端出現(xiàn)了軟鍵盤(pán)輸完隱藏后頁(yè)面不會(huì)回彈,下方會(huì)有一大塊留白。這篇文章主要介紹了決微信H5頁(yè)面軟鍵盤(pán)彈起后頁(yè)面下方留白的問(wèn)題(iOS端) ,需要的朋友可以參考下
    2019-06-06
  • Vue3中的動(dòng)畫(huà)過(guò)渡實(shí)現(xiàn)技巧分享

    Vue3中的動(dòng)畫(huà)過(guò)渡實(shí)現(xiàn)技巧分享

    在現(xiàn)代的前端開(kāi)發(fā)中,用戶(hù)體驗(yàn)的重要性不言而喻,為了讓?xiě)?yīng)用程序更加生動(dòng)和引人注目,動(dòng)畫(huà)和過(guò)渡效果是必不可少的元素,本文將以 Vue3 為基礎(chǔ),深入探討如何在應(yīng)用程序中實(shí)現(xiàn)動(dòng)畫(huà)過(guò)渡,以及一些技巧和最佳實(shí)踐,需要的朋友可以參考下
    2025-01-01
  • vue分頁(yè)插件的使用方法

    vue分頁(yè)插件的使用方法

    這篇文章主要介紹了vue分頁(yè)插件的使用方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • Vue下拉菜單組件化開(kāi)發(fā)詳解

    Vue下拉菜單組件化開(kāi)發(fā)詳解

    這篇文章主要為大家詳細(xì)介紹了Vue下拉菜單組件化開(kāi)發(fā)過(guò)程,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 通過(guò)vue如何設(shè)置header

    通過(guò)vue如何設(shè)置header

    這篇文章主要介紹了通過(guò)vue如何設(shè)置header,每個(gè)項(xiàng)目都有頭部但是內(nèi)容不一樣;這種情況我們可以考慮在app.vue中創(chuàng)建公共頭部,那么怎么配置公共頭部header,下面小編通過(guò)實(shí)例代碼詳細(xì)講解,需要的朋友可以參考下
    2023-02-02
  • 詳解使用webpack打包編寫(xiě)一個(gè)vue-toast插件

    詳解使用webpack打包編寫(xiě)一個(gè)vue-toast插件

    本篇文章主要介紹了詳解使用webpack打包編寫(xiě)一個(gè)vue插件,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-11-11
  • vue商城中商品“篩選器”功能的實(shí)現(xiàn)代碼

    vue商城中商品“篩選器”功能的實(shí)現(xiàn)代碼

    這篇文章主要介紹了vue商城中商品“篩選器”功能的實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • vue-router 源碼之實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 vue-router

    vue-router 源碼之實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 vue-router

    這篇文章主要介紹了vue-router 源碼之實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 vue-router,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07

最新評(píng)論