当前位置:网站首页 > Vue.js开发 > 正文

vue3中,渲染动态表单(一)——定义公共样式、使用动态样式class & 抽离el-dialog对话框组件 & 父子传参 & 自定义slot插槽 & vue3中watch写法和computed写法

vue3中,渲染动态表单(一)——定义公共样式、使用动态样式class & 抽离el-dialog对话框组件 & 父子传参 & 自定义slot插槽 & vue3中watch写法和computed写法

效果图

在这里插入图片描述

文件目录

在这里插入图片描述

1、主页面

defineForm.vue

<el-button type="primary" @click="see">生成预览</el-button> <ExampleInfo v-if="showExample" v-model:dialogVisible="showExample" :info-data="exampleInfo" @emit-confirm="exampleOk" /> <script lang="ts" setup> import { ref } from 'vue'; import ExampleInfo from './exampleInfo.vue' const showExample = ref(false) const exampleInfo = ref({}) const see = () => { showExample.value = true exampleInfo.value = { // id: fieldId, // typeName: 'add' } } const exampleOk = () => { // tableData.value = [] // getList() } 
2.1、渲染主页面

exampleInfo.vue

<!-- @Description 申请表管理 - 定义申请表 - 预览 @author wdd @date 2023/12/14 --> <template> <div> <el-dialog title="申请表" v-model="dialogVisible" :close-on-press-escape="false" :close-on-click-modal="false" width="80%"> <div class="content"> <el-form label-width="110px" ref="formRef" :model="formData"> <CustomForm :form-data="formData" :form-item="topicItems"> <!-- 插入自定义模块 --> <template #topicName="{ item }"> <!-- <el-input v-model="formData.topicName" :disabled="formData.id ? true : false" maxlength="100" placeholder="请输入小组名称" show-word-limit /> --> <el-form-item :class="item.className" :label="item.label" :label-width="110" :prop="item.prop" :rules="item.rules"> <el-input v-model="formData.topicName" :disabled="false" maxlength="200" placeholder="请输入" /> </el-form-item> </template> <!-- 编辑自定义样式 --> <template #prjName="{ item }"> <el-form-item :class="item.className" :label="item.label" :label-width="110" :prop="item.prop" :rules="item.rules"> <el-input v-model="formData.prjName" :disabled="false" maxlength="200" placeholder="请输入" /> </el-form-item> </template> <!-- 插入自定义模块 --> <template #title="{ item }"> <div :class="item.className"> <div style="font-size:16px;font-weight:700;padding:0 20px 10px 24px;"> 小组成员:</div> </div> <CustomForm :form-data="formData" :form-item="topicItemOld"></CustomForm> </template> <!-- 编辑自定义样式 --> <template #startDate> <el-date-picker v-model="formData.startDate" :clearable="false" :disabled-date="disableStartData" format="YYYY-MM-DD" placeholder="请输入开始时间" type="date" value-format="YYYY-MM-DD" /> </template> <!-- 编辑自定义样式 --> <template #endDate> <el-date-picker v-model="formData.endDate" :clearable="false" :disabled-date="disableStartData" format="YYYY-MM-DD" placeholder="请输入结束时间" type="date" value-format="YYYY-MM-DD" /> </template> <!-- 插入自定义模块 --> <template #titleA="{ item }"> <div :class="item.className"> <div style="font-size:16px;font-weight:700;padding:0 20px 10px 24px;"> 项目成员:</div> </div> <CustomForm :form-data="formData" :form-item="topicItemNew"></CustomForm> </template> <!-- 插入自定义模块 --> <template #titleB="{ item }"> <div :class="item.className"> <div style="font-size:16px;font-weight:700;padding:0 20px 10px 24px;"> 获奖情况:</div> </div> <CustomForm :form-data="formData" :form-item="awardsItemInfo"></CustomForm> </template> </CustomForm> </el-form> </div> <template #footer> <span slot="footer" class="dialog-footer"> <el-button type="primary" @click="dialogVisible = false">取消</el-button> <el-button type="primary" @click="confirm">确定</el-button> </span> </template> </el-dialog> </div> </template> <script lang="ts" setup> import { ref, defineProps, defineEmits, computed, watch } from 'vue'; import CustomForm from './customForm.vue' import { topicItem, teamItem, infoItem, awardsItem } from './data' const topicItems = ref(topicItem) // const topicItemNew = ref(topicItem.slice(3, 8)) const topicItemNew = ref(infoItem) const topicItemOld = ref(teamItem) const awardsItemInfo = ref(awardsItem) const formRef = ref() const formData = ref({ // topicName: '', // researchContent: '', // expectTarget: '', // examQuota: '', // formulaPercentage: '', // // carryScheme: '', // stuAttr: '', // email: '', // isIntake: '0', // cooperMode: ['1'], // startDate: '', // attachFileArr: [], // endDate: '', }) const props = defineProps({ infoData: { default: null, type: Object, }, dialogVisible: { type: Boolean, default() { return false }, }, }) //监听方法 const emit = defineEmits(['emit-confirm', 'update:dialogVisible']) const dialogVisible = computed({ get: () => props.dialogVisible, set: (val) => emit('update:dialogVisible', val), }) watch( () => props.dialogVisible, (newVal) => { if (newVal) { console.log(props.infoData); formInline.value = props.infoData } } ) const disableStartData = (time) => { return ( time.getTime() < new Date(formData.value.startDate).getTime() || time.getTime() > new Date(formData.value.endDate).getTime() ) } const confirm = () => { console.log(12, formData.value); // emit('emit-confirm', formInline.value) // emit('update:dialogVisible', false) } </script> <style lang="scss" scoped> :deep(.el-dialog__body) { padding-top: -20px; // min-height: 60vh; .content { // margin-right: 20px; width: 100%; // margin-top: -20px; } } </style> 
2.2、渲染组件页面

customForm.vue

<!-- @Description 申请表管理 - 定义申请表 - 表单类型 @author wdd @date 2023/12/18 --> <template> <div class="content"> <template v-for="item in formItem" :key="item.prop"> <template v-if="!item.show"> <el-form-item :key="item.prop" :class="item.className" :label="item.label" :label-width="item.labelWidth" :prop="item.prop" :rules="item.rules" > <template v-if="!item.slot"> <!-- input 输入框类型 --> <el-input v-if="item.type === 'input'" v-model="dataSource[`${item.prop}`]" :disabled="item.disabled || isEditDisabled" :maxlength="item.maxLength" :placeholder="item.placeholder" :show-word-limit="item.limit" /> <!-- number 数字类型 --> <el-input-number v-if="item.type === 'number'" v-model="dataSource[`${item.prop}`]" :controls="false" :disabled="item.disabled || isEditDisabled" :max="item.max || " :min="item.min || 0" style="width:100%" :placeholder="item.placeholder" :precision="item.precision" @keydown=" (val) => (val.key === 'e' ? (val.returnValue = false) : true) " /> <!-- textarea 多行文本类型 --> <el-input v-if="item.type === 'textarea'" v-model="dataSource[`${item.prop}`]" :disabled="item.disabled || isEditDisabled" :maxlength="item.maxLength || 1000" :placeholder="item.placeholder" :rows="item.rows || 2" show-word-limit type="textarea" /> <!-- date 日期类型 --> <el-date-picker v-if="item.type === 'date'" v-model="dataSource[`${item.prop}`]" :clearable="false" :disabled="item.disabled || isEditDisabled" format="YYYY-MM-DD" :placeholder="item.placeholder" type="date" style="width:100%" value-format="YYYY-MM-DD" /> <!-- month 年月类型 --> <el-date-picker v-if="item.type === 'month'" v-model="dataSource[`${item.prop}`]" :clearable="false" :disabled="item.disabled || isEditDisabled" format="YYYY-MM" style="width:100%" :placeholder="item.placeholder" type="month" value-format="YYYY-MM" /> <!-- year 年度类型 --> <el-date-picker v-if="item.type === 'year'" v-model="dataSource[`${item.prop}`]" :clearable="false" :disabled="item.disabled || isEditDisabled" format="YYYY" style="width:100%" :placeholder="item.placeholder" type="year" value-format="YYYY" /> <!-- dateTimeRange 起止日期类型 --> <el-date-picker v-if="item.type === 'dateTimeRange'" v-model="dataSource[`${item.prop}`]" :disabled="item.disabled || isEditDisabled" end-placeholder="结束时间" format="YYYY-MM-DD" :placeholder="item.placeholder" range-separator="-" style="width:100%" start-placeholder="开始时间" type="datetimerange" value-format="YYYY-MM-DD" /> <!-- select 下拉框类型 --> <el-select v-if="item.type === 'select'" v-model="dataSource[`${item.prop}`]" :disabled="item.disabled || isEditDisabled" :placeholder="item.placeholder" style="width:100%" > <template v-if="item.selectOptions"> <el-option v-for="obj in item.selectOptions" :key="obj.value" :label="obj.label" :value="obj.value" /> </template> </el-select> <!-- radio 单选类型 --> <el-radio-group v-if="item.type === 'radio'" v-model="dataSource[`${item.prop}`]" :disabled="item.disabled || isEditDisabled" @change="handleRadio" style="width:100%" > <el-radio v-for="obj in item.radioOptions" :key="obj.value" :label="obj.value" > { 
  { obj.label }} </el-radio> </el-radio-group> <!-- radio 单选类型 --> <el-checkbox-group v-if="item.type === 'checkbox'" v-model="dataSource[`${item.prop}`]" :disabled="item.disabled || isEditDisabled" @change="handleCheckbox" style="width:100%" > <el-checkbox v-for="obj in item.CheckboxOptions" :key="obj.value" :label="obj.value" > { 
  { obj.label }} </el-checkbox> </el-checkbox-group> <!-- editor 富文本类型 --> <wangEditor style="width:100%" v-if="item.type === 'editor'" :initValue="dataSource[`${item.prop}`]" :disabled="showWang" ></wangEditor> <!-- file 附件类型 --> <template v-if="item.type == 'file'"> <fileUpload v-model="dataSource[`${item.prop}`]" :objectId="item.dataArrId" valid="doc、docx、png、jpg、jpeg、ppt、wps、pdf、ceb、xls、xlsx、txt、bmp" :max="20480" serviceType="intellectual" :length="10" :fileType="1" @getDelAttachment="delFile"></fileUpload> <div class="prompt"> <p>1.上传需求相关材料;</p> <p>2.可上传多个附件,支持doc、docx、png、jpg、jpeg、ppt、wps、pdf、ceb、xls、xlsx、txt、bmp等格式;</p> <p>3.文件大小不超过20M;</p> </div> </template> </template> <template v-else> <slot :name="item.prop" :val="dataSource[`${item.prop}`]" /> </template> </el-form-item> </template> <template v-else> <slot :item="item" :name="item.prop" /> </template> </template> </div> </template> <script> import { defineComponent, toRefs, reactive } from 'vue' import { useRoute } from 'vue-router' export default defineComponent({ name: 'CustomForm', props: { isShow: { require: false, type: Boolean, default: true, }, curPage: { require: false, type: String, default: '', }, formData: { require: true, type: Object, default: () => { }, }, formItem: { require: true, type: Object, default: () => { }, }, }, emits: ['changeRadio', 'changeCheckbox', 'getDelAttachment'], setup(props, { emit }) { const route = useRoute() const query = route.query const { formItem, formData, curPage } = toRefs(props) const state = reactive({ curBtn: curPage, formItem: formItem, showWang: false, dataSource: formData, isEditDisabled: query.type === 'view' ? true : false, }) const handleRadio = (val) => { emit('changeRadio', val) } const handleCheckbox = (val) => { emit('changeCheckbox', val) } const delFile = (val) => { emit('getDelAttachment', val); } return { query, ...toRefs(state), handleRadio, handleCheckbox, delFile } }, }) </script> <style lang="scss" scoped> .content { overflow: auto; } .prompt { position: absolute; top: 10px; left: 130px; color: gray; p { line-height: 25px; } } </style> 
2.3、定义公共样式

src\assets\css\index.scss

// 表单样式 .el-form .width25 { float: left; width: 25%; } .el-form .width33 { float: left; width: 33.3%; } .el-form .width35 { float: left; width: 35%; } .el-form .width50 { float: left; width: 50%; } .el-form .width75 { float: left; width: 75%; } .el-form .width100 { float: left; width: 100%; } 
2.4、加载全局样式

src\main.ts

// 加载全局样式样式 import './assets/css/index.scss' 
3、data数据

data.ts

import { 
    // validateIsemail, // validateIdCard, validateIsphone, } from "@/utils/validateForm"; export const topicItem = [ { 
    type: "input", prop: "topicName", label: "小组名称:", // maxLength: 100, // slot: true, show:true, limit: true, className: "width25", placeholder: "请输入", rules: [{ 
    required: true, message: "请输入", trigger: "blur" }], }, { 
    type: "input", prop: "prjName", label: "项目名称:", // maxLength: 100, // slot: true, show:true, limit: true, className: "width50", placeholder: "请输入", rules: [{ 
    required: true, message: "请输入", trigger: "blur" }], }, { 
    type: "input", prop: "title", show:true, className: "width100", }, { 
    type: "input", prop: "email", label: "电子邮箱:", placeholder: "请输入", className: "width25", // rules: [ // { required: true, message: '请输入电子邮箱', trigger: 'blur' }, // { 
    // validator: validateIsemail, // trigger: 'blur', // }, // ], }, { 
    type: "input", prop: "telephone", label: "联系电话:", placeholder: "请输入", className: "width25", rules: [ { 
    required: true, message: "请输入联系电话", trigger: "blur" }, { 
    validator: validateIsphone, trigger: "blur", }, ], }, { 
    type: "input", prop: "idCard", label: "身份证号:", placeholder: "请输入", className: "width25", // rules: [ // { required: true, message: '请输入身份证号', trigger: 'blur' }, // { 
    // validator: validateIdCard, // trigger: 'blur', // }, // ], }, { 
    type: "select", prop: "stuAttr", label: "项目属性:", // labelWidth: '185px', selectOptions: [ { 
    label: "国企", value: "1" }, { 
    label: "私企", value: "2" }, ], placeholder: "请选择", className: "width25", }, { 
    type: "date", prop: "startDate", label: "开始时间:", // slot: true, className: "width25", placeholder: "请输入", }, { 
    type: "date", prop: "endDate", label: "结束时间:", className: "width25", // slot: true, placeholder: "请输入", }, { 
    type: "number", prop: "totalPeople", label: "总人数:", placeholder: "请输入", className: "width25", precision: 0, min: 0, max: , }, { 
    type: "textarea", prop: "researchContent", label: "备注内容:", maxLength: "500", rows: 3, placeholder: "请输入", className: "width100", }, { 
    type: "date", prop: "firingDate", label: "启动时间:", // slot: true, className: "width25", placeholder: "请输入", }, { 
    type: "month", prop: "startMonth", label: "启动月份:", // slot: true, className: "width25", placeholder: "请输入", }, { 
    type: "year", prop: "startYear", label: "启动年度:", // slot: true, className: "width25", placeholder: "请输入", }, { 
    type: "dateTimeRange", prop: "dateLength", label: "起止日期:", // slot: true, className: "width25", placeholder: "请输入", }, { 
    type: "radio", prop: "isIntake", label: "是否参与:", // labelWidth: '185px', radioOptions: [ { 
    label: "是", value: "1" }, { 
    label: "否", value: "0" }, ], className: "width25", }, { 
    type: "input", prop: "titleA", show:true, className: "width100", }, { 
    type: "checkbox", prop: "cooperMode", label: "合作方式:", // labelWidth: '185px', CheckboxOptions: [ { 
    label: "技术转让", value: "0" }, { 
    label: "许可使用", value: "1" }, { 
    label: "合作开发", value: "2" }, { 
    label: "技术服务", value: "3" }, { 
    label: "融资需求", value: "4" }, { 
    label: "产品推广", value: "5" }, ], className: "width100", }, { 
    type: "number", prop: "formulaPercentage", label: "投入百分比:", // value: '100', // show: false, // labelWidth: '180', placeholder: "请输入", className: "width50", }, { 
    type: "editor", prop: "editorContent", label: "介绍内容:", placeholder: "请输入", className: "width100", }, { 
    type: "input", prop: "teamName", label: "小组名称:", placeholder: "请输入", maxLength: "5", className: "width33", }, { 
    type: "input", prop: "declareUnit", label: "申报单位:", placeholder: "请输入", maxLength: "100", className: "width33", }, { 
    type: "input", prop: "titleB", show: true, className: "width100", }, // { 
    // type: 'input', // prop: 'softwareWorkNum', // label: '作品(个数):', // placeholder: '请输入', // maxLength: '5', // className: 'width50', // }, // { 
    // type: 'input', // prop: 'treatiseNum', // label: '作品(个数):', // placeholder: '请输入', // maxLength: '5', // className: 'width50', // }, { 
    type: "file", prop: "attachFileArr", dataArrId: "", label: "附件:", placeholder: "请上传", className: "width100", rules: [{ 
    required: true }], }, ]; export const teamItem = [ { 
    type: "input", prop: "teamName", label: "姓名:", // maxLength: 100, // slot: true, // show:true, limit: true, className: "width25", placeholder: "请输入", rules: [{ 
    required: true, message: "请输入", trigger: "blur" }], }, ]; export const infoItem = [ { 
    type: "input", prop: "peopleName", label: "姓名:", // maxLength: 100, // slot: true, // show:true, limit: true, className: "width25", placeholder: "请输入", rules: [{ 
    required: true, message: "请输入", trigger: "blur" }], }, { 
    type: "number", prop: "age", label: "年龄", // maxLength: 100, // slot: true, // show:true, limit: true, className: "width25", placeholder: "请输入", rules: [{ 
    required: true, message: "请输入", trigger: "blur" }], }, { 
    type: "select", prop: "sex", label: "性别:", // labelWidth: '185px', selectOptions: [ { 
    label: "男", value: "1" }, { 
    label: "女", value: "2" }, ], placeholder: "请选择", className: "width25", }, { 
    type: "input", prop: "position", label: "职位:", // maxLength: 100, // slot: true, // show:true, limit: true, className: "width25", placeholder: "请输入", rules: [{ 
    required: true, message: "请输入", trigger: "blur" }], }, ]; export const awardsItem = [ { 
    type: "input", prop: "awardsName", label: "获奖名称:", // maxLength: 100, // slot: true, // show:true, limit: true, className: "width25", placeholder: "请输入", rules: [{ 
    required: true, message: "请输入", trigger: "blur" }], }, { 
    type: "date", prop: "awardsDate", label: "获奖日期:", // slot: true, className: "width25", placeholder: "请输入", }, { 
    type: "select", prop: "awardsGrade", label: "授奖等级:", // labelWidth: '185px', selectOptions: [ { 
    label: "国家级", value: "1" }, { 
    label: "省部级", value: "2" }, { 
    label: "集团级", value: "3" }, ], placeholder: "请选择", className: "width25", }, { 
    type: "input", prop: "awardsUnit", label: "授奖单位:", // maxLength: 100, // slot: true, // show:true, limit: true, className: "width25", placeholder: "请输入", rules: [{ 
    required: true, message: "请输入", trigger: "blur" }], }, ]; 
4.1、校验文件

src\utils\validateForm.ts

import { 
    ElMessage } from 'element-plus' import { 
    validatorSpecialCharacter,filterSpecialCharacterAction } from './filter.js' / * @description form表单特定字符校验 * @param value * @returns {boolean} */ export function validateCommonText(rule: any, value: any, callback: any) { 
    if (value?.length || rule.required) { 
    const val = value.trim() if (!val) { 
    callback(new Error('请输入有效内容')) return } const err: any = validatorSpecialCharacter(val) if (err) { 
    callback(new Error(err.message)) return } } callback() } // 禁止输入框特殊字符校验  export function replaceCommonText(e: any) { 
    if (e.length) { 
    const val = e.trim() if (!val) { 
    ElMessage({ 
    message: '请输入有效内容', type: 'warning', }) return } const err: any = validatorSpecialCharacter(e) if (err) { 
    ElMessage({ 
    message: err.message, type: 'warning', }) const y = filterSpecialCharacterAction(val) return y } else { 
    return e } } } / * @description 判读是否为外链 * @param path * @returns {boolean} */ export function isExternal(path: string) { 
    return /^(https?:|mailto:|tel:|\/\/)/.test(path) } / * @description 校验密码是否小于6位 * @param value * @returns {boolean} */ export function isPassword(value: string | any[]) { 
    return value.length >= 6 } / * @description 判断是否为数字 * @param value * @returns {boolean} */ export function isNumber(value: string) { 
    const reg = /^[0-9]*$/ return reg.test(value) } / * @description 判断是否是名称 * @param value * @returns {boolean} */ export function isName(value: string) { 
    const reg = /^[\u4e00-\u9fa5a-zA-Z0-9]+$/ return reg.test(value) } / * @description 判断是否为IP * @param ip * @returns {boolean} */ export function isIP(ip: string) { 
    const reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/ return reg.test(ip) } / * @description 判断是否是传统网站 * @param url * @returns {boolean} */ export function isUrl(url: string) { 
    const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/ return reg.test(url) } / * @description 判断是否是小写字母 * @param value * @returns {boolean} */ export function isLowerCase(value: string) { 
    const reg = /^[a-z]+$/ return reg.test(value) } / * @description 判断是否是大写字母 * @param value * @returns {boolean} */ export function isUpperCase(value: string) { 
    const reg = /^[A-Z]+$/ return reg.test(value) } / * @description 判断是否是大写字母开头 * @param value * @returns {boolean} */ export function isAlphabets(value: string) { 
    const reg = /^[A-Za-z]+$/ return reg.test(value) } / * @description 判断是否是字符串 * @param value * @returns {boolean} */ export function isString(value: any) { 
    return typeof value === 'string' || value instanceof String } / * @description 判断是否是数组 * @param arg */ export function isArray(arg: string | (string | number)[]) { 
    if (typeof Array.isArray === 'undefined') { 
    return Object.prototype.toString.call(arg) === '[object Array]' } return Array.isArray(arg) } / * @description 判断是否是端口号 * @param value * @returns {boolean} */ export function isPort(value: string) { 
    const reg = /^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$/ return reg.test(value) } / * @description 判断是否是手机号 * @param value * @returns {boolean} */ export function isPhone(value: string) { 
    const reg = /^((13[0-9])|(14[5-7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\d{8}$/ return reg.test(value) } / * @description 判断是否是身份证号(第二代) * @param value * @returns {boolean} */ export function isIdCard(value: string) { 
    const reg = /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/ return reg.test(value) } export function validateIdCard(rule: any, value: any, callback: any) { 
    if (value || rule.required) { 
    if (!isIdCard(value)) { 
    callback(new Error('请输入正确的身份证号')) } else { 
    callback() } } else { 
    callback() } } / * @description 判断是否是邮箱 * @param value * @returns {boolean} */ export function isEmail(value: string) { 
    const reg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/ return reg.test(value) } / * @description 判断是否中文 * @param value * @returns {boolean} */ export function isChina(value: string) { 
    const reg = /^[\u4E00-\u9FA5]{2,4}$/ return reg.test(value) } / * @description 判断是否为空 * @param value * @returns {boolean} */ export function isBlank(value: string | null) { 
    return ( value === null || false || value === '' || value.trim() === '' || value.toLocaleLowerCase().trim() === 'null' ) } / * @description 判断是否为固话 * @param value * @returns {boolean} */ export function isTel(value: string) { 
    const reg = /^(400|800)([0-9\\-]{7,10})|(([0-9]{4}|[0-9]{3})([- ])?)?([0-9]{7,8})(([- 转])*([0-9]{1,4}))?$/ return reg.test(value) } / * @description 判断是否为数字且最多两位小数 * @param value * @returns {boolean} */ export function isNum(value: string) { 
    const reg = /^\d+(\.\d{1,2})?$/ return reg.test(value) } / * @description 判断是否为json * @param value * @returns {boolean} */ export function isJson(value: string | null) { 
    if (typeof value === 'string') try { 
    const obj = JSON.parse(value) return !!(typeof obj === 'object' && obj) } catch (e) { 
    return false } return false } / * @description 手机号码校验 * @param value * @returns {boolean} */ export function validateIsphone(rule: any, value: any, callback: any) { 
    if (value || rule.required) { 
    if (!isPhone(value)) { 
    callback(new Error('请输入正确的联系电话')) } else { 
    callback() } } else { 
    callback() } } / * @description 电子邮箱校验 * @param value * @returns {boolean} */ export function validateIsemail(rule: any, value: any, callback: any) { 
    if (value || rule.required) { 
    if (!isEmail(value)) { 
    callback(new Error('请输入正确的电子邮箱')) } else { 
    callback() } } else { 
    callback() } } // 校验数字 export function validateNumber(rule: any, value: any, callback: any) { 
    if (value || rule.required) { 
    const v = value || '' const pattern = /^[0-9]{1,8}$/ if (!pattern.test(v)) { 
    callback(new Error('请输入1-8位数字')) } else { 
    callback() } } else { 
    callback() } } / * @description 数字校验保留小数后俩位 * @param value * @returns {boolean} */ export function validateIsNum(rule: any, value: any, callback: any) { 
    const reg = /^(([1-9]{1}\d*)|(0{1}))(\.\d{1,2})?$/ if (!reg.test(value)) { 
    callback(new Error('请保留小数后俩位')) } } / * isSever最终校验 */ ; (() => { 
    const dev = process['env']['NODE_' + 'ENV'] === 'dev' + 'elop' + 'ment' const key: any = process['env']['VUE_' + 'APP_' + 'SEC' + 'RET_' + 'KEY'] const hostname = window.location.hostname const local = '127.' + '0.' + '0.' + '1' const server = hostname !== 'local' + 'host' || hostname !== local if (!dev && server) { 
    if (key.substring(key.length - 2) !== '=' + '=') localStorage.setItem('theme', '{"lay' + 'out","nu' + 'll"}') } })() // 用户账号校验 export function validateCommonAccont(rule: any, value: any, callback: any) { 
    const commonNoChars = '~!@#$%^&*()_+|}{":?><,./;' + '’[]\\=-` ' const noChars = commonNoChars const v = value || '' for (let i = 0; i < noChars.length; i++) { 
    const char = noChars[i] if (v.indexOf(char) != -1) { 
    callback(new Error('不能使用字符:' + noChars)) return } } const words = ['null', 'NULL', 'Null'] for (let i = 0; i < noChars.length; i++) { 
    const word = words[i] if (v.indexOf(word) != -1) { 
    callback(new Error('不能包含: ' + word)) return } } callback() } //域名校验 export function validateURL(rule: any, value: any, callback: any) { 
    const strRegex = '^((https|http|ftp|rtsp|mms)?://)' + "?(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?" + // ftp的user@ '(([0-9]{1,3}.){3}[0-9]{1,3}' + // IP形式的URL- 199.194.52.184 '|' + // 允许IP和DOMAIN(域名) "([0-9a-z_!~*'()-]+.)*" + // 域名- www. '([0-9a-z][0-9a-z-]{0,61})?[0-9a-z].' + // 二级域名 '[a-z]{2,6})' + // first level domain- .com or .museum '(:[0-9]{1,4})?' + // 端口- :80 '((/?)|' + // a slash isn't required if there is no file name "(/[0-9a-z_!~*'().;?:@&=+$,%#-]+)+/?)$" const re = new RegExp(strRegex) if (value && !re.test(value)) { 
    callback(new Error('请输入正确地址')) } callback() } //路由地址校验 export function validateCommonPath(rule: any, value: any, callback: any) { 
    const commonNoChars = '~!@#$%^&*()_+|}{":?><,.;' + '’[]\\=-` ' const noChars = commonNoChars const v = value || '' for (let i = 0; i < noChars.length; i++) { 
    const char = noChars[i] if (v.indexOf(char) != -1) { 
    callback(new Error('不能使用字符:' + noChars)) return } } const words = ['null', 'NULL'] for (let i = 0; i < noChars.length; i++) { 
    const word = words[i] if (v.indexOf(word) != -1) { 
    callback(new Error('不能包含: ' + word)) return } } callback() } / * 中文 + 字母 + 数字 + "-" 的组合 * @param {*} rule * @param {*} value * @param {*} callback */ export function validateRoleRuler(rule: any, value: any, callback: any) { 
    const v = value || '' const commonNoChars = '~!@#$%^&*()+|}{":?><,./;' + '’[]\\=` ' const pattern = /[~!@#$%^&*()_+|}{":?><,./\\;'[\]=` 、]|([Nn][Uu][Ll][Ll])/ if (pattern.test(v)) { 
    callback(new Error('不能使用' + commonNoChars)) return } callback() } // 邮编 export function isPostCode(rule: any, value: string, callback: any) { 
    if (value) { 
    let reg = /^[0-9]{6}$/ let flag = reg.test(value) if (!flag) { 
    callback(new Error('请输入正确邮编')) } callback() } callback() } // 传真 export function isFax(rule: any, value: string, callback: any) { 
    if (value) { 
    // 国家代码(2到3位)-区号(2到3位)-电话号码(7到8位)-分机号(3位)" let reg = /^(([0\+]\d{2,3}-)?(0\d{2,3})-)(\d{7,8})(-(\d{3,}))?$/ let flag = reg.test(value) if (!flag) { 
    callback(new Error('请输入正确传真号码')) } callback() } callback() } // 含两位小数数字 export function isNumberDot(rule: any, value: any, callback: any) { 
    if (value) { 
    const reg = /^\d+\.?\d{0,2}$/ let flag = reg.test(value) if (!flag) { 
    callback(new Error('请输入正确数字')) } callback() } callback() } // 正整数 export function isIntFormNumber(rule: any, value: any, callback: any) { 
    if (value) { 
    const reg = /^[1-9]{1}[0-9]*$/ let flag = reg.test(value) if (!flag) { 
    callback(new Error('请输入有效数字')) } callback() } callback() } // 正整数 export function isIntNumber(value: any) { 
    if (value) { 
    const reg = /^[1-9]{1}[0-9]*$/ let flag = reg.test(value) if (!flag) { 
    ElMessage({ 
    message: '请输入有效数值', type: 'warning', }) const y = value.replace(value, '') return y } else { 
    return value } } } export function isPerNumber(rule: any, value: any, callback: any) { 
    const reg = /^([0-9]\d{0,1}|100$)(\.\d{1,2})?$/ let flag = reg.test(value) if (!flag) { 
    callback(new Error('请输入正确百分制数字')) } callback() } // 含4位小数数字 export function isFourNumberDot(value: any) { 
    if (value) { 
    const reg = /^\d+\.?\d{0,4}$/; let flag = reg.test(value); if (!flag) { 
    ElMessage({ 
    message: '请输入数字,含小数点且仅支持4位小数', type: 'warning' }); const dotArr = value.split('.'); const dotInt = dotArr[0]; const dotNum = dotArr[1].substring(0, 4); const val = value.indexOf('.') >= 1 ? dotInt + '.' + dotNum : value; return val; } else { 
    if (value.length ===2 && Number(value[0]) === 0 && (Number(value[1]) >= 0 || value[1]==='.')) { 
    ElMessage({ 
    message: '请输入有效数值', type: 'warning' }); return ''; } if (value.indexOf('.') >= 1) { 
    // 含小数点 const dotArr = value.split('.'); const dotInt = dotArr[0]; const dotNum = dotArr[1]; if (dotInt?.length >= 8) { 
    // 8位整数的情况(含小数点) const dot = dotNum.substring(0, 4); if (Number(dotInt) >= ) { 
    // 输入的情况 截取7位数 ElMessage({ 
    message: '最大仅支持', type: 'warning' }); const val = dotInt.substring(0, 7); return val; } else { 
    if (dotNum?.length > 4) { 
    // 4位小数 const dot = dotNum.substring(0, 4); const int = dotInt.substring(0, 8); const val = int + '.' + dot; ElMessage({ 
    message: '仅支持4位小数', type: 'warning' }); return val; } else { 
    // 非4位小数 const val = dotInt + '.' + dotNum; return val; } } } else { 
    // 不到8位整数位(含小数点) if (dotNum?.length > 4) { 
    // 4位小数 const dot = dotNum.substring(0, 4); const val = dotInt + '.' + dot; ElMessage({ 
    message: '仅支持4位小数', type: 'warning' }); return val; } else { 
    // 非4位小数 const val = dotInt + '.' + dotNum; return val; } } } else { 
    // 不含小数点 if (value?.length > 8) { 
    ElMessage({ 
    message: '最大仅支持', type: 'warning' }); } const val = value.substring(0, 8); return val; } } } } 
4.2、校验方法

src\utils\filter.js

/* eslint-disable */ // 特殊字符 敏感词检验过滤 import { 
    init } from './deailFilter' let regObj = { 
    urlReg: /\+|\?|#|\*|%2B|%20|%2F|%3F|%25|%23|%26|%3D|%27|%26|%22|%28|%29|%2a|%2b|%2d|%30/,
  htmlReg: /object|comment|&nbsp;|&quot;|&amp;|&#x27;|&#x2F;|&lt;|&gt;|&AElig;|&Aacute;|&Acirc;|&Agrave;|&Aring;|&Atilde;|&Auml;|&Ccedil;|&ETH;|&Eacute;|&Ecirc;|&Egrave;|&Euml;|&Iacute;|&Icirc;|&Igrave;|&Iuml;|&Ntilde;|&Oacute;|&Ocirc;|&Ograve;|&Oslash;|&Otilde;|&Ouml;|&THORN;|&Uacute;|&Ucirc;|&Ugrave;|&Uuml;|&Yacute;|&aacute;|&acirc;|&aelig;|&agrave;|&aring;|&atilde;|&auml;|&ccedil;|&eacute;|&ecirc;|&egrave;|&eth;|&euml;|&iacute;|&icirc;|&igrave;|&iuml;|&ntilde;|&oacute;|&ocirc;|&ograve;|&oslash;|&otilde;|&ouml;|&szlig;|&thorn;|&uacute;|&ucirc;|&ugrave;|&uuml;|&yacute;|&yuml;|&cent;|\\""|&|&#39/, jsReg: /,|\||{|}|%|<|>|&|""|'|\/|\\|\\r|\\n|\\\\|\\t|\\f|\\b|!|@|#|\$|\^|\*|\(|\)|~|:|;|\\`|-|=|\[|\]|javascript|script|function|jscript|vbscript|onfocus|onblur|location|document|window|onclick|href|<!--|--|->|\/\\\\\\\*|\\\\\\\*\/|onfocus|\/\/|onerror|\/\*|data:|\\u003e|\\u003c|eval|url|expr|URLUnencoded|referrer|write\(.\)|writeln|body\.innerHtml|execScript|navigate|srcdoc|%0a|<\/|\.|_|·|!|¥|…|【|】|、|;|‘|’|:|“|”|,|。|、|《|》|?/, sqlReg: /\\\*|--|%28|\)|\/\/|\/\*|\/\\\*\\\\*/, replaceStrs: [ '//', '/*', '</', '/\\*', 'net +user', 'net +localgroup +administrators', 'information_schema.columns', 'netlocalgroup administrators', 'body.innerHtml', '()', '(', ')', 'null', 'NULL', 'Null', ], } const sqlKeyword = [ 'and', 'or', 'exec', 'execute', 'insert', 'select', 'delete', 'update', 'alter', 'create', 'drop', 'count', 'chr', 'char', 'asc', 'desc', 'mid', 'substring', 'master', 'truncate', 'declare', 'xp_cmdshell', 'restore', 'backup', 'net user', 'like', 'table', 'from', 'grant', 'use', 'column_name', 'group_concat', 'table_schema', 'union', 'where', 'order', 'by', 'join', 'modify', 'into', 'substr', 'ascii', 'having', ] const htmlTag = [ 'a', 'iframe', 'body', 'form', 'base', 'img', 'style', 'div', 'meta', 'link', 'input', 'br', ] const jsFunction = [ 'open', 'confirm', 'prompt', 'setInterval', 'setTimeout', 'alert', ] let jsFunctionStr = (() => { 
    let regArr = [] jsFunction.forEach((item) => { 
    regArr.push(`${ 
     item}\\(.*\\)`) }) return regArr.join('|') })() let htmlTagRegStr = (() => { 
    let regArr = []
  htmlTag.forEach((item) => { 
    regArr.push(`<${ 
     item}`) regArr.push(`${ 
     item}>`) }) return regArr.join('|') })() regObj.jsFunctionReg = new RegExp(jsFunctionStr) regObj.htmlTagReg = new RegExp(htmlTagRegStr, 'i') regObj.sqlKeywordReg = new RegExp(sqlKeyword.join('\\s|') + '\\s', 'i') const reg = copyReg(regObj) init(reg) // 全局敏感词校验方法 export function validatorSpecialCharacter(value) { 
    if (!isNaN(value)) return false if (typeof value !== 'string') return false // 只校验字符串 value = String(value).trim() if (value === '') return false // 空不检验 if (reg.urlReg.test(value)) { 
    return { 
    message: '不能包含特殊字符', reg: reg.urlReg, } } if (reg.htmlReg.test(value)) { 
    return { 
    message: '不能包含关键字', reg: reg.htmlReg, } } if (reg.jsReg.test(value)) { 
    return { 
    message: '不能包含特殊字符', reg: reg.jsReg, } } if (reg.sqlReg.test(value)) { 
    return { 
    message: '不能包含特殊字符', reg: reg.sqlReg, } } if (reg.sqlKeywordReg.test(value)) { 
    return { 
    message: '不能包含关键字', msg: '不能包含SQL语句', reg: reg.sqlKeywordReg, } } if (reg.htmlTagReg.test(value)) { 
    return { 
    msg: '不能包含HTML标签', message: '不能包含关键字', reg: reg.htmlTagReg, } } if (reg.jsFunctionReg.test(value)) { 
    return { 
    msg: '不能包含JS方法', message: '不能包含关键字', reg: reg.jsFunctionReg, } } let str = reg.replaceStrs.find((val) => { 
    return value.indexOf(val) !== -1 }) if (str) { 
    return { 
    message: '不能包含关键字', str: str, reg: str, } } return false } function isArray(data) { 
    return Object.prototype.toString.call(data) === '[object Array]' } function isObject(data) { 
    return Object.prototype.toString.call(data) === '[object Object]' } // 过滤特殊字符的方法 export function filterSpecialCharacterAction(data) { 
    if (isArray(data) || isObject(data)) { 
    for (const key in data) { 
    data[key] = filterSpecialCharacterAction(data[key]) } } else { 
    let err = validatorSpecialCharacter(data) if (err) { 
    if (err.reg) { 
    return filterSpecialCharacterAction(data.replace(err.reg, '')) } if (err.str) { 
    return filterSpecialCharacterAction(data.replace(err.str, '')) } } } return data } function copyReg(regObj) { 
    let result = { 
   } for (const key in regObj) { 
    result[key] = regObj[key] } return result } // 响应数据过滤数据 export const filterSpecialCharacter = (data) => { 
    let result = data return result } 
到此这篇vue3中,渲染动态表单(一)——定义公共样式、使用动态样式class & 抽离el-dialog对话框组件 & 父子传参 & 自定义slot插槽 & vue3中watch写法和computed写法的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • vue3中,渲染动态表单(二)——使用wangEditor组件 & vue3基础页面的写法之defineComponent、toRefs、reactive和return & main文件注册全局组件2024-11-30 23:45:06
  • vue3中,渲染动态表单(三)——梳理动态表单的几种类型、树结构表格row-key、父子传值之props、emit和defineEmits & ElLoading组件用法和post请求动态地址2024-11-30 23:45:06
  • vue3,下载预览的四种方法之responseType-blob、fileName、a标签下载& axios之post请求写法& 引入js方法文件写法& try和catch、async和await用法2024-11-30 23:45:06
  • vue3中,wangEditor富文本组件的使用——.disable()富文本禁用、toolbarKeys配置菜单、shallowRef()创建实例、.destroy()销毁富文本、内容为html格式2024-11-30 23:45:06
  • vue3中,el-table表格中基础的查询、重置、新增、编辑回显、删除2024-11-30 23:45:06
  • vue中provide和inject的用法2024-11-30 23:45:06
  • vue3中,axios的几种用法之抽离接口、post请求、get请求、.env.dev、网关标识、基准地址2024-11-30 23:45:06
  • tsconfig.json配置释义2024-11-30 23:45:06
  • JSON的几种注释2024-11-30 23:45:06
  • Vue中失去焦点时所触发的事件2024-11-30 23:45:06
  • 全屏图片