ant-design表单处理和常用方法及自定义验证操作

首先要说一下antdesign这个框架API和demo丰富,而且开发环境提供对应的warning来纠正用户的错误。是一个很好的组件库。

关于表单验证方面是依赖于 async-validator 库。百度的san-xui组件库的表单验证也是依赖与async-validator。说明这个库的实用性还是比较高,可以多了解一下。

首先按照antDesign官网Demo。我们可以copy一个Form表单的demo。 LoginForm是表单的组件,下面代码,是React 高阶组件(Hoc)。 用于使组件获取 this.props.form

下面介绍一些常用的 this.props.form的方法。

const { form } = this.props

form.resetFields() 用于清空输入空

form.validateFields 用于验证

1.给输入框添加 键名。rules 规定输入规则。 validator可以自定义输入标准

value 标识输入内容

callback 回调函数,如果里面有字符串,代表错误提示。如果为空。代表输入正确 成功返回。

补充知识:Ant Design Pro Vue使用心得

目录结构

├── public

│ └── logo.png # LOGO

| └── index.html # Vue 入口模板

├── src

│ ├── api # Api ajax 等

│ ├── assets # 本地静态资源

│ ├── config # 项目基础配置,包含路由,全局设置

│ ├── components # 业务通用组件

│ ├── core # 项目引导, 全局配置初始化,依赖包引入等

│ ├── router # Vue-Router

│ ├── store # Vuex

│ ├── utils # 工具库

│ ├── locales # 国际化资源

│ ├── views # 业务页面入口和常用模板

│ ├── App.vue # Vue 模板入口

│ └── main.js # Vue 入口 JS

│ └── permission.js # 路由守卫(路由权限控制)

├── tests # 测试工具

├── README.md

└── package.json

路由和菜单

基本结构

路由和菜单是组织起一个应用的关键骨架,pro 中的路由为了方便管理,使用了中心化的方式,在 router.config.js 统一配置和管理。

路由管理 通过约定的语法根据在router.config.js中配置路由。

菜单生成 根据路由配置来生成菜单。菜单项名称,嵌套路径与路由高度耦合。

面包屑 组件 PageHeader 中内置的面包屑也可由脚手架提供的配置信息自动生成。

路由

目前脚手架中所有的路由都通过 router.config.js 来统一管理,在 vue-router 的配置中我们增加了一些参数,如 hideChildrenInMenu,meta.title,meta.icon,meta.permission,来辅助生成菜单。其中:

hideChildrenInMenu 用于隐藏不需要在菜单中展示的子路由。用法可以查看 分步表单 的配置。

hidden 可以在菜单中不展示这个路由,包括子路由。效果可以查看 other 下的路由配置。

meta.title 和 meta.icon分别代表生成菜单项的文本和图标。

meta.permission 用来配置这个路由的权限,如果配置了将会验证当前用户的权限,并决定是否展示 *(默认情况下)。

meta.hidden 可以强制子菜单不显示在菜单上(和父级 hideChildrenInMenu 配合)

meta.hiddenHeaderContent 可以强制当前页面不显示 PageHeader 组件中的页面带的 面包屑和页面标题栏

路由配置项

/**
* 路由配置说明:
* 建议:sider menu 请不要超过三级菜单,若超过三级菜单,则应该设计为顶部主菜单 配合左侧次级菜单
*
**/
{
redirect: noredirect, //重定向
name: 'router-name', //路由名称
hidden: true, //可以在菜单中不展示这个路由,包括子路由。效果可以查看 other 下的路由配置。
meta: {
title: 'title', //菜单项名称
icon: 'a-icon', //菜单项图标
keepAlive: true, //缓存页面
permission:[string] //用来配置这个路由的权限,如果配置了将会验证当前用户的权限,并决定是否展示 *(默认情况下)
hiddenHeaderContent: true, //可以强制当前页面不显示 PageHeader 组件中的页面带的 面包屑和页面标题栏
}
}

具体请参考 https://pro.loacg.com/docs/router-and-nav

菜单

菜单根据 router.config.js 生成,具体逻辑在 src/store/modules/permission.js 中的 actions.GenerateRoutes 方法实现。

Ant Design Pro 的布局

在 Ant Design Pro 中,我们抽离了使用过程中的通用布局,都放在 /components/layouts 目录中,分别为:

BasicLayout:基础页面布局,包含了头部导航,侧边栏和通知栏:

UserLayout:抽离出用于登陆注册页面的通用布局

PageView:基础布局,包含了面包屑,和中间内容区 (slot)

RouterView:空布局,专门为了二级菜单内容区自定义

BlankLayout:空白的布局

定义全局样式

/* 定义全局样式 */
:global(.text) {
 font-size: 16px;
}

/* 定义多个全局样式 */
:global {
 .footer {
 color: #ccc;
 }
 .sider {
 background: #ebebeb;
 }
}
//覆盖组件样式
// 使用 css 时可以用 >>> 进行样式穿透
.test-wrapper >>> .ant-select {
 font-size: 16px;
}

// 使用 scss, less 时,可以用 /deep/ 进行样式穿透
.test-wrapper /deep/ .ant-select {
 font-size: 16px;
}

// less CSS modules 时亦可用 :global 进行覆盖
.test-wrapper {
 :global {
  .ant-select {
   font-size: 16px;
  }
 }
}

与服务器交互

在 Ant Design Pro 中,一个完整的前端 UI 交互到服务端处理流程是这样的:

UI 组件交互操作;

调用统一管理的 api service 请求函数;

使用封装的 request.js 发送请求;

获取服务端返回;

更新 data。

从上面的流程可以看出,为了方便管理维护,统一的请求处理都放在 @/src/api 文件夹中,并且一般按照 model 纬度进行拆分文件,如:

api/

user.js

permission.js

goods.js

...

其中,@/src/utils/request.js 是基于 axios 的封装,便于统一处理 POST,GET 等请求参数,请求头,以及错误提示信息等。具体可以参看 request.js。 它封装了全局 request 拦截器、response 拦截器、统一的错误处理、baseURL 设置等。

例如在 api 中的一个请求用户信息的例子:

// api/user.js
import { axios } fromm '@/utils/request'

const api = {
 info: '/user',
 list: '/users'
}

// 根据用户 id 获取用户信息
export function getUser (id) {
 return axios({
  url: `${api.user}/${id}`,
  method: 'get'
 })
}

// 增加用户
export function addUser (parameter) {
 return axios({
  url: api.user,
  method: 'post',
  data: parameter
 })
}

// 更新用户 // or (id, parameter)
export function updateUser (parameter) {
 return axios({
  url: `${api.user}/${parameter.id}`, // or `${api.user}/${id}`
  method: 'put',
  data: parameter
 })
}

// 删除用户
export function deleteUser (id) {
 return axios({
  url: `${api.user}/${id}`,
  method: 'delete',
  data: parameter
 })
}

// 获取用户列表 parameter: { pageSize: 10, pageNo: 1 }
export function getUsers (parameter) {
 return axios({
  url: api.list,
  method: 'get',
  params: parameter
 })
}
<template>
 <div>
  <a-button @click="queryUser"></a-button>

  <a-table :dataSource="list">
  </a-table>
 </div>
</template>

<script>
import { getUser, getUsers } from '@/api/user'

export default {
 data () {
  return {
   id: 0,
   queryParam: {
    pageSize: 10,
    pageNo: 1,
    username: ''
   },
   info: {},
   list: []
  }
 },
 methods: {
  queryUser () {
   const { $message } = this
   getUser(this.id).then(res => {
    this.info = res.data
   }).catch(err => {
    $message.error(`load user err: ${err.message}`)
   })
  },
  queryUsers () {
   getUsers(this.queryParam).then(res => {
    this.list = res
   })
  }
 }
}
</script>
**
  * 获取裁剪后的图片
  */
 cropImage () {
  this.form.cropimg = this.$refs.cropper.getCroppedCanvas().toDataURL();
 },
 /**
  * 确认裁剪
  */
 sureCrop () {
  this.dialogVisible = false
 },
 /**
  * 上传裁剪后的图片到服务器
  */
 upCropImg () {
  //判断是否是新增还是编辑
  if (this.$route.query.id && this.$route.query.id != '') {
  //如果是编辑的就直接提交
  this.onSubmit()
  } else {
  //否则先上传裁剪图片,将64位图片转换为二进制数据流
  var formdata1 = new FormData();// 创建form对象
  formdata1.append('file', convertBase64UrlToBlob(this.form.cropimg), 'aaa.png');//
  this.$ajax
   .post(this.$api + "/upload/singleUploadImg", formdata1, { headers: { 'Content-Type': 'multipart/form-data' } })
   .then(response => {
   if (response.data.msg == "success" && response.data.code == 1) {
    this.form.imgUrl = response.data.data.imgUrl
    this.onSubmit()
   } else {
    console.log(response)
    this.$message.error(response.data.msg);
   }
   })
   .catch(function (error) {
   console.log(error);
   });
  }

 },

引入外部模块

$ npm install '组件名字' --save

使用

//全局引入
import Vue from 'vue'
import VueQuillEditor from 'vue-quill-editor'

// require styles
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'

Vue.use(VueQuillEditor, /* { default global options } */)
<template>
<div>
<quill-editor ref="myTextEditor"
v-model="content"
:config="editorOption"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@ready="onEditorReady($event)">
</quill-editor>
</div>
</template>
<script>
//按需加载
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
import { quillEditor } from 'vue-quill-editor'

export default {
 components: {
 quillEditor
 },
 data () {
  return {
   content: '<h2>I am Example</h2>',
   editorOption: {
   // something config
   }
  }
 },
 // 如果需要手动控制数据同步,父组件需要显式地处理changed事件
 methods: {
 onEditorBlur(editor) {
  console.log('editor blur!', editor)
 },
 onEditorFocus(editor) {
  console.log('editor focus!', editor)
 },
 onEditorReady(editor) {
  console.log('editor ready!', editor)
 },
 onEditorChange({ editor, html, text }) {
  // console.log('editor change!', editor, html, text)
  this.content = html
 }
 },
 // 如果你需要得到当前的editor对象来做一些事情,你可以像下面这样定义一个方法属性来获取当前的editor对象,实际上这里的$refs对应的是当前组件内所有关联了ref属性的组件元素对象
 computed: {
 editor() {
  return this.$refs.myTextEditor.quillEditor
 }
 },
 mounted() {
 // you can use current editor object to do something(editor methods)
 console.log('this is my editor', this.editor)
 // this.editor to do something...
 }
}
</script>

引入业务图标

参考:https://pro.loacg.com/docs/biz-icon、

国际化

参考:https://pro.loacg.com/docs/i18n

权限管理

参考:https://pro.loacg.com/docs/authority-management

自定义使用规则

修改网站icon的文件地址在 public文件夹中把logo.png换成自定义的,也可在public/index.html自定义

<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>logo.png" rel="external nofollow" >
<title>共享云店</title>
<style>#loading-mask{position:fixed;left:0;top:0;height:100%;width:100%;background:#fff;user-select:none;z-index:9999;overflow:hidden}.loading-wrapper{position:absolute;top:50%;left:50%;transform:translate(-50%,-100%)}.loading-dot{animation:antRotate 1.2s infinite linear;transform:rotate(45deg);position:relative;display:inline-block;font-size:64px;width:64px;height:64px;box-sizing:border-box}.loading-dot i{width:22px;height:22px;position:absolute;display:block;background-color:#1890ff;border-radius:100%;transform:scale(.75);transform-origin:50% 50%;opacity:.3;animation:antSpinMove 1s infinite linear alternate}.loading-dot i:nth-child(1){top:0;left:0}.loading-dot i:nth-child(2){top:0;right:0;-webkit-animation-delay:.4s;animation-delay:.4s}.loading-dot i:nth-child(3){right:0;bottom:0;-webkit-animation-delay:.8s;animation-delay:.8s}.loading-dot i:nth-child(4){bottom:0;left:0;-webkit-animation-delay:1.2s;animation-delay:1.2s}@keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@-webkit-keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@keyframes antSpinMove{to{opacity:1}}@-webkit-keyframes antSpinMove{to{opacity:1}}</style>
</head>
<body>
<noscript>
<strong>We're sorry but vue-antd-pro doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app">
<div id="loading-mask">
<div class="loading-wrapper">
<span class="loading-dot loading-dot-spin"><i></i><i></i><i></i><i></i></span>
</div>
</div>
</div>
<!-- built files will be auto injected -->
</body>
</html>

-更换logo在src\components\tools\Logo.vue中更换

<template>
 <div class="logo">
 <router-link :to="{name:'dashboard'}">
  <LogoSvg alt="logo" /> //这是logo
  <h1 v-if="showTitle">{{ title }}</h1> //这是网站标题
 </router-link>
 </div>
</template>

<script>
import LogoSvg from '@/assets/logo.svg?inline';
export default {
 name: 'Logo',
 components: {
 LogoSvg
 },
 props: {
 title: {
  type: String,
  default: 'Admin For Ok', //网站默认标题
  required: false
 },
 showTitle: {     //是否显示网站标题,默认不显示
  type: Boolean,
  default: true,
  required: false
 }
 }
}
</script>

pro权限管理和路由控制思路分析(粗略分析)

主要是通过三个文件实现,src\mock\services\user.js文件通过登陆的角色获取对应的鉴权规则,具体可查看该文件下的源码

src\config\router.config.js文件为路由配置文件,可增加路由取消路由等,变量asyncRouterMap为主要路由数组集合,可配置鉴权权限,变量constantRouterMap为基础路由,不参与鉴权

src\permission.js文件为动态配置路由的主要逻辑,代码如下

import Vue from 'vue'
import router from './router'
import store from './store'

import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import notification from 'ant-design-vue/es/notification'
import { setDocumentTitle, domTitle } from '@/utils/domUtil'
import { ACCESS_TOKEN } from '@/store/mutation-types'

NProgress.configure({ showSpinner: false }) // NProgress Configuration

const whiteList = ['login', 'register', 'registerResult'] // no redirect whitelist配置白名单

router.beforeEach((to, from, next) => {
 NProgress.start() // start progress bar
 //生成动态网站标题
 to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${to.meta.title} - ${domTitle}`))
 if (Vue.ls.get(ACCESS_TOKEN)) {
 /* has token 如果有token并且是从登录页来的就直接跳到工作空间*/
 if (to.path === '/user/login') {
  next({ path: '/dashboard/workplace' })
  NProgress.done()
 } else {
 //否则检测是不是没有检测到规则,请求获取用户信息,获取用户权限
  if (store.getters.roles.length === 0) {
  //请求mock模拟数据获取用户权限
  store
   .dispatch('GetInfo')
   .then(res => {
   const roles = res.result && res.result.role
   //调用src\store\modules\permission.js里面的GenerateRoutes方法,处理数据
   store.dispatch('GenerateRoutes', { roles }).then(() => {
    // 根据roles权限生成可访问的路由表
    // 动态添加可访问路由表
    router.addRoutes(store.getters.addRouters)
    const redirect = decodeURIComponent(from.query.redirect || to.path)
    if (to.path === redirect) {
    // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
    next({ ...to, replace: true })
    } else {
    // 跳转到目的路由
    next({ path: redirect })
    }
   })
   })
   .catch(() => {
   notification.error({
    message: '错误',
    description: '请求用户信息失败,请重试'
   })
   store.dispatch('Logout').then(() => {
    next({ path: '/user/login', query: { redirect: to.fullPath } })
   })
   })
  } else {
  next()
  }
 }
 } else {
 if (whiteList.includes(to.name)) {
  // 在免登录白名单,直接进入
  next()
 } else {
  next({ path: '/user/login', query: { redirect: to.fullPath } })
  NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
 }
 }
})

router.afterEach(() => {
 NProgress.done() // finish progress bar
})

src\store\modules\permission.js文件为路由数据的详细处理逻辑,配合src\permission.js文件使用,代码如下: import { asyncRouterMap, constantRouterMap } from '@/config/router.config'

/**
 * 过滤账户是否拥有某一个权限,并将菜单从加载列表移除
 *
 * @param permission
 * @param route
 * @returns {boolean}
 */
function hasPermission (permission, route) {
 if (route.meta && route.meta.permission) {
 let flag = false
 for (let i = 0, len = permission.length; i < len; i++) {
  flag = route.meta.permission.includes(permission[i])
  if (flag) {
  return true
  }
 }
 return false
 }
 return true
}

/**
 * 单账户多角色时,使用该方法可过滤角色不存在的菜单
 *
 * @param roles
 * @param route
 * @returns {*}
 */
// eslint-disable-next-line
function hasRole(roles, route) {
 if (route.meta && route.meta.roles) {
 return route.meta.roles.includes(roles.id)
 } else {
 return true
 }
}

function filterAsyncRouter (routerMap, roles) {
 const accessedRouters = routerMap.filter(route => {
 if (hasPermission(roles.permissionList, route)) {
  if (route.children && route.children.length) {
  route.children = filterAsyncRouter(route.children, roles)
  }
  return true
 }
 return false
 })
 return accessedRouters
}

const permission = {
 state: {
 routers: constantRouterMap,
 addRouters: []
 },
 mutations: {
 SET_ROUTERS: (state, routers) => {
  state.addRouters = routers
  state.routers = constantRouterMap.concat(routers)
 }
 },
 actions: {
 GenerateRoutes ({ commit }, data) {
  return new Promise(resolve => {
  const { roles } = data
  const accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
  commit('SET_ROUTERS', accessedRouters)
  resolve()
  })
 }
 }
}
export default permission

跨域请求设置

在vue.config.js文件中修改

 // 配置跨域
 devServer: {
 // development server port 8000
 // port: 8000,
 proxy: {
  '/apis': {
  // target: 'https://mock.ihx.me/mock/5baf3052f7da7e07e04a5116/antd-pro',
  target: 'http://192.168.1.73:8092/okcloud/',
  // target: 'http://39.107.78.120:8083/okcloud/',

  ws: false,
  changeOrigin: true, //是否允许跨域
  pathRewrite: {
   '^/apis': ''
  }
  }
 }

axios拦截器

在文件src\utils\request.js中设置

// request interceptor
service.interceptors.request.use(config => {
 const token = Vue.ls.get(ACCESS_TOKEN)
 if (token) {
 config.headers['okcloud_token'] = token // 让每个请求携带自定义 token 请根据实际情况自行修改
 }
 return config
}, err)

// response interceptor
service.interceptors.response.use((response) => {
 if (response.data.code === 10000) {
 notification.warning({
  message: '提示',
  description: response.data.message
 })
 } else {
 return response.data
 }
}, err)

自定义角色的菜单权限

在src\main.js文件中注释掉"// import ‘./permission' // permission control 权限控制"

自定义路由权限文件src\routeGuard.js,代码如下

import Vue from 'vue'
import router from './router'
// import store from './store'

import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { setDocumentTitle, domTitle } from '@/utils/domUtil'
import { ACCESS_TOKEN } from '@/store/mutation-types'

NProgress.configure({ showSpinner: false }) // NProgress Configuration

router.beforeEach((to, from, next) => {
 NProgress.start() // start progress bar
 to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${to.meta.title} - ${domTitle}`))
 if (to.path === '/user/login' && Vue.ls.get(ACCESS_TOKEN)) {
 next({ path: '/dashboard/workplace' })
 NProgress.done()
 } else if (to.path !== '/user/login' && !Vue.ls.get(ACCESS_TOKEN)) {
 next({ path: '/user/login' })
 NProgress.done()
 } else {
 next()
 NProgress.done()
 }
})
router.afterEach(() => {
 NProgress.done() // finish progress bar
})

在main.js中引入import ‘./routeGuard'

对src\components\Menu\menu.js文件进行自定义菜单改造

在src\store\modules\app.js文件中store加入menu,在actions中进行获取菜单的异步操作,获取菜单信息,然后进行全局变量动态获取

在src\layouts\BasicLayout.vue中进行全局变量的引用

 ...mapState({
  // 动态主路由
  menus: state => state.app.menu
 }),

动态方法的引用

...mapActions(['setSidebar', 'setMenu']),

调用获取动态方法

this.setMenu()

以上这篇ant-design表单处理和常用方法及自定义验证操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 解决ant design vue中树形控件defaultExpandAll设置无效的问题

    页面步骤: 1.设置a-tree标签 2.默认的treeNodes值设置为空数组 3.在mounted组件加载的时候给treeNodes的值赋值 结果: 设置defaultExpandAll无效,并不能展开所有节点 原因: defaultExpandAll 仅在组件第一次渲染时有效,不仅仅tree组件,其它组件的defaultXXX值都是这个行为, 可以自行搜索受控组件/非受控组件的概念.如果你想异步获取数据后展开全部结点,可以使用非受控方式: https://codepen.io/lovefe

  • Ant Design的Table组件去除

    在Ant Design的Table组件文档中,排序有三种状态:点击升序.点击降序.取消排序.一般需求只需要升序和降序,不需要取消排序,这时候就需要我们设置sortOrder来去除取消排序. 首先,我们从官方文档中ctrl+c出一个排序栗子,放在我们的组件中. 官方栗子 import React, { useEffect, useState } from 'react'; import { Table } from 'antd' export default () => { const [data

  • ant-design-vue 时间选择器赋值默认时间的操作

    我就废话不多说了,大家还是直接看代码吧~ <template> <div> <a-range-picker show-time format="YYYY/MM/DD HH:mm:ss" :value="[this.moment(startTime, dateFormat),this.moment(endTime, dateFormat)]" //关键代码 @change="onChangeTime" ><

  • ant design vue中日期选择框混合时间选择器的用法说明

    首先时间格式化用到moment方法,需要在页面中引入moment组件 import moment from 'moment' 结构代码: <a-date-picker style="width:100%" :getCalendarContainer="(triggerNode) => triggerNode.parentNode" format="YYYY-MM-DD HH:mm:ss" v-decorator="[ 'pu

  • ant design 日期格式化的实现

    今天写项目的时候用到ant design中的日期组件,但是由于用ant design日期组件取得的值是moment类型,而往数据库中保存需要的是字符串类型.这里就用到了moment日期转换 第一种写法 我取得的值是年月 如:201806 第二种写法 moment().format('YYYY-MM-DD') 第三种写法 moment(Date.now()).format('YYYY-MM-DD') 获取本地日期的下个月 window.moment().add(1, 'months') 获取当前日

  • 基于ant design日期控件使用_仅月份的操作

    总体效果: 展开后: 选值后: 代码部分: 1.引入: import { DatePicker } from 'antd'; 2.主体部分: export default class PersonInfo extends Component{ constructor() { super(); //设置状态,存储日期 this.state = { workMode: ['month', 'month'], workValue: [], }; } render(){ //主体引用 const {Ra

  • ant-design表单处理和常用方法及自定义验证操作

    首先要说一下antdesign这个框架API和demo丰富,而且开发环境提供对应的warning来纠正用户的错误.是一个很好的组件库. 关于表单验证方面是依赖于 async-validator 库.百度的san-xui组件库的表单验证也是依赖与async-validator.说明这个库的实用性还是比较高,可以多了解一下. 首先按照antDesign官网Demo.我们可以copy一个Form表单的demo. LoginForm是表单的组件,下面代码,是React 高阶组件(Hoc). 用于使组件获

  • Ant Design_Form表单上传文件组件实现详解

    目录 背景 实现 问题1: 问题2: tip1:注意一下新增和修改时校验方法 tip2: 注意一下beforeUpload的返回值 背景 需要实现的需求:在一个表单提交中,需要提交各种组件的提交信息,其中包括上传文件:一般呢,我们会在选择文件的时候将文件先传到服务器,拿到文件的URL,在提交表单的时候传的其实是文件的URL: 刚开始,对文件没有必填的校验,是比较简单的:但是后来要求文件是必传的,需要加上文件的校验,就暴漏了一些小问题: 实现 首先,先对Upload组件加上必传的校验 rules=

  • JSP实现用于自动生成表单标签html代码的自定义表单标签

    本文实例讲述了JSP实现用于自动生成表单标签html代码的自定义表单标签.分享给大家供大家参考.具体如下: 这个是自己写的一个简单的JSP表单标签,用于自动生成checkbox,select,radio等标签,传入菜单集合生成html代码,自动选中指定值,用于java web项目的jsp页面. 1. Servlet部分代码: Map<String, String> map = new HashMap<String, String>(); map.put("2",

  • 利用JS提交表单的几种方法和验证(必看篇)

    工作中发现表单提交方便的问题,很多时候IE下提交好好的,打了火狐下就出现了问题,利用提交按钮就不成功了,于是利用JS的方式就成功了,也不知道为什么.在导师的催促下就总结出以下的几种常用表单提交的方法. 第一种方式:表单提交,在form标签中增加onsubmit事件来判断表单提交是否成功 <script type="text/javascript"> function validate(obj) { if (confirm("提交表单?")) { aler

  • vue+elementUI实现表单和图片上传及验证功能示例

    本文实例讲述了vue+elementUI实现表单和图片上传及验证功能.分享给大家供大家参考,具体如下: 最终实现需求如下图: form表单内容与重点人员图片同时上传且图片为必填项 分析弹框页需要解决的问题有: 1.表单内容的验证及必填项 2.新增和编辑用同一个组件如何处理数据 3.图片需要和信息一起传递(即不允许自动上传) 4.图片必填的验证问题 针对上述问题作出方案: 1.el-form的表单验证需要注意几个地方: a:el-form-item的prop值需要和表单标签的v-model值保持一

  • layui在form表单页面通过Validform加入简单验证的方法

    form简单验证 <input type="text" name="email" datatype="e" ignore="ignore" placeholder="请输入邮箱" autocomplete="off" class="layui-input"> datatype="e"验证邮箱 ignore="ignore&qu

  • vue用elementui写form表单时,在label里添加空格操作

    要在密码两字中间添加空格,发现直接添加  是识别不了的,正确写法为: 代码: <el-form-item label="密 码:" :label-width="formLabelWidth" prop="password"> <label slot="label">密    码:</label> <el-input type="password" v-model=&

  • react使用antd表单赋值,用于修改弹框的操作

    1.使用getFieldDecorator的initialValue 2.在state里定义一个变量存表格的数据 3.给打开弹框的方法传个record 4.把表格里的值存到state 5.把在state里存的值传给弹框 6.获取传过来的值 7.在取消方法和修改成功后中给赋空值,要不然,点击添加的方法表单里面会有值 7.OK 补充知识:react中使用antd的表单重置数据 resetFields 重置一组输入控件的值(为 initialValue)与状态,如不传入参数,则重置所有组件 Funct

  • 解决antd 表单设置默认值initialValue后验证失效的问题

    方法一: getFieldDecorator没有第三个参数,如果写了3个参数就会出错 错误代码: <Form.Item> { getFieldDecorator('userName', { initialValue: 'Tom' },{ rules: [{ required: true, message: '请输入用户名', }], })( <Input placeholder='请输入用户名'/> ) } </Form.Item> 正确代码: <Form.Ite

随机推荐