您好,登錄后才能下訂單哦!
本篇內容介紹了“vue ant design封裝彈窗表單如何使用”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
<template> <div id="formForm"> <a-modal :visible="true" :title='title' @ok="handleOk('ok')" @cancel="handleOk('return')" :centered="true" :confirmLoading="confirmLoading" :width="width"> <a-form :form="formState" :label-col="{ span: 5 }" :wrapper-col="{ span: 17 }"> <div v-for="itme in formData" :key="itme.value" > <!-- 輸入款 --> <a-form-item :label="itme.label" v-if="itme.type === 'input'" :label-col="{ span: itme.labelCol ? itme.labelCol : 5 }" :wrapper-col="{ span: itme.wrapper ? itme.wrapper : 17 }"> <a-input v-decorator="[itme.value, { rules: [{ required: itme.required?itme.required:false, message: itme.message?itme.message:' ' }, {validator: itme.validator}]}]" :placeholder="!itme.placeholder ? itme.label : itme.label" allowClear> <!-- 插入輸入框的下拉框選擇器 --> <a-select v-if="itme.select && itme.select.length>0" slot="addonBefore" v-decorator="[ itme.header ]" > <a-select-option v-for="select in itme.select" :key="select.value"> {{select.label}} </a-select-option> </a-select> </a-input> </a-form-item> <!-- 開始結束時間選擇 --> <a-form-item :label="itme.label" v-if="itme.type === 'rangePicker'"> <a-range-picker :placeholder="!itme.placeholder ? itme.label : itme.placeholder" showTime : v-decorator="[itme.value, { rules: [{ required: itme.required?itme.required:false, message: itme.message?itme.message:' ' }]}]" /> </a-form-item> <!-- 單個時間選擇 --> <a-form-item :label="itme.label" v-if="itme.type === 'datePicker'"> <a-date-picker : v-decorator="[ itme.value, { rules: [{ required: itme.required?itme.required:false, message: itme.message?itme.message:' ' }]}]" showTime :placeholder="!itme.placeholder ? itme.label : itme.placeholder" /> </a-form-item> <!-- 選擇框 --> <a-form-item :label="itme.label" v-if="itme.type === 'select'" :label-col="{ span: itme.labelCol ? itme.labelCol : 5 }" :wrapper-col="{ span: itme.wrapper ? itme.wrapper : 8 }"> <a-select allowClear v-decorator="[ itme.value, { rules: [{ required: itme.required?itme.required:false, message: itme.message?itme.message:' ' }]}]" :placeholder="!itme.placeholder ? itme.label : itme.placeholder"> <a-select-option v-for="optionItme in itme.option" :key="optionItme.value"> {{optionItme.label}} </a-select-option> </a-select> </a-form-item> <!-- 單選框 --> <a-form-item :label="itme.label" v-if="itme.type === 'radio'"> <a-radio-group v-decorator="[ itme.value, { rules: [{ required: itme.required?itme.required:false, message: itme.message?itme.message:' ' }]}]"> <a-radio v-for="radioItme in itme.radio" :key="radioItme.value" :value="radioItme.value"> {{radioItme.label}} </a-radio> </a-radio-group> </a-form-item> <!-- 開關按鈕 --> <a-form-item :label="itme.label" v-if="itme.type === 'switch'"> <a-switch v-decorator="[ itme.value, { valuePropName: 'checked' }]" /> </a-form-item> <!-- 圖片上傳 --> <a-form-item :label="itme.label" v-if="itme.type === 'upload'" :label-col="{ span: itme.labelCol ? itme.labelCol : 5 }" :wrapper-col="{ span: itme.wrapper ? itme.wrapper : 20 }"> <a-upload v-decorator="[ itme.value, { valuePropName: 'fileList', getValueFromEvent: normFile, }]" :action="itme.action?itme.action:'https://www.mocky.io/v2/5cc8019d300000980a055e76'" listType="picture-card" @preview="handlePreview"> <div v-if="itme.value.length < 8"> <a-icon type="plus" /> <div class="ant-upload-text">點擊上傳圖片</div> </div> </a-upload> <a-modal :visible="previewVisible" :footer="null" @cancel="previewVisible = false"> <img alt="example" :src="previewImage" /> </a-modal> </a-form-item> </div> </a-form> </a-modal> </div> </template>
<script lang='ts'> import { Component, Vue, Prop, Emit, Watch } from 'vue-property-decorator'; import Moment from 'moment' function getBase64(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => resolve(reader.result); reader.onerror = error => reject(error); }); } @Component({ data() { return { formState: this.$form.createForm(this), previewVisible: false, previewImage: '' }; }, }) export default class FormForm extends Vue { [x: string]: any; // 彈出框寬度 @Prop({type: String, default: '500px'}) width!: string; // 接收表單渲染內容數據 @Prop({type: Object, default: () => {console.log()}}) form!: {}; // 接收彈窗窗口標題 @Prop({type: String, default: '操作窗口'}) title!: string; // 接收表單渲染內容格式 @Prop({type: Array, default: () => []}) formData!: []; // 返出取消和確定按鈕 @Emit('handleOk') handleOk(e) { if (e === 'return') { return 'true'; } else if (e === 'ok') { let stateType: object | boolean = false; this.formState.validateFields((err, value) => { if (!err) { this.confirmLoading = true; stateType = value; } }) return stateType; } } // 監聽表單渲染內容數據接入 + 轉換多余傳入問題 @Watch('form', {immediate: true, deep: false}) onForm(e) { let obj: object = {}; Object.keys(e).forEach(key => { Array.from(this.formData).forEach((res: any | object) => { if (key === res.value || key === res.header) { if (res.type === 'rangePicker' && e[key].length > 0) { e[key] = [ Moment(e[key][0]), Moment(e[key][1]) ] } if (res.type === 'datePicker' && e[key]) { e[key] = Moment(e[key]) } obj[key] = e[key] } }) }) this.$nextTick(() => { this.formState.setFieldsValue(obj) }) } // 監聽是否彈窗屬性 public visibleOff: boolean = false; // 確定按鈕loading public confirmLoading: boolean = false; // --------- methods ------------ async handlePreview(file) { if (!file.url && !file.preview) { file.preview = await getBase64(file.originFileObj); } this.previewImage = file.url || file.preview; this.previewVisible = true; } normFile(e) { if (Array.isArray(e)) { return e; } return e && e.fileList; } } </script>
<style lang='scss' scpoed> .ant-form-item-label{ white-space: pre-wrap; line-height: 25px; } .ant-row{ display: flex; align-items: center; } .ant-form{ max-height: 60vh; overflow: auto; &::-webkit-scrollbar { display: none;; } } .ant-form-item{ margin-bottom: 10px; } .ant-form-item-control{ left: 10px; max-height: 225px; overflow: auto; &::-webkit-scrollbar{ display: none; } } .ant-upload-select-picture-card i { font-size: 32px; color: #999; } .ant-upload-select-picture-card .ant-upload-text { margin-top: 8px; color: #666; } </style>
部分效果圖:
vue create antd-demo
所以,得到了這么一個項目,如下
npm install --save ant-design-vue@next
修改main.ts
import { createApp } from 'vue'; import App from './App.vue'; import Antd from "ant-design-vue"; import "ant-design-vue/dist/antd.css"; createApp(App).use(Antd).mount('#app');
修改App.vue
<template> <HelloWorld/> </template>
<script lang="ts"> import { defineComponent } from 'vue'; import HelloWorld from './components/HelloWorld.vue'; export default defineComponent({ name: 'App', components: { HelloWorld } }); </script>
<style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
修改HelloWorld.vue
<template> <a-form layout="inline" :model="formState" @finish="handleFinish" @finishFailed="handleFinishFailed" > <a-form-item> <a-input v-model:value="formState.user" placeholder="Username"> <template #prefix><UserOutlined /></template> </a-input> </a-form-item> <a-form-item> <a-input v-model:value="formState.password" type="password" placeholder="Password"> <template #prefix><LockOutlined /></template> </a-input> </a-form-item> <a-form-item> <a-button type="primary" html-type="submit" :disabled="formState.user === '' || formState.password === ''" > Log in </a-button> </a-form-item> </a-form> </template>
<script lang="ts"> import { UserOutlined, LockOutlined } from '@ant-design/icons-vue'; import { ValidateErrorEntity } from 'ant-design-vue/es/form/interface'; import { defineComponent, reactive, UnwrapRef } from 'vue'; interface FormState { user: string; password: string; } export default defineComponent({ setup() { const formState: UnwrapRef<FormState> = reactive({ user: '', password: '', }); const handleFinish = (values: FormState) => { console.log(values, formState); }; const handleFinishFailed = (errors: ValidateErrorEntity<FormState>) => { console.log(errors); }; return { formState, handleFinish, handleFinishFailed, }; }, components: { UserOutlined, LockOutlined, }, }); </script>
npm run serve啟動應用,效果如下
好了,應用就暫時介紹到這里。其實,我更想說說我的疑惑:
Hello.vue中,Username輸入框的前面有個圖片前綴,Password輸入框的前面也有一個圖片前綴,都是通過<template #prefix></template>實現的,一眼看去,應該就是通過插槽實現的,但是具體的實現過程是怎樣的,尚不清楚。
簡單調試了一下,如下圖所示。
ant-design-vue的Form組件的FormItem.js的部分源碼如下,
“vue ant design封裝彈窗表單如何使用”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。