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


Posted in Javascript onOctober 27, 2020

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

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

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

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

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

const { form } = this.props

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

form.validateFields 用于验证

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

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

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

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表单处理和常用方法及自定义验证操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
extJs 常用到的增,删,改,查操作代码
Dec 28 Javascript
获取内联和链接中的样式(js代码)
Apr 11 Javascript
JavaScript中的常见问题解决方法(乱码,IE缓存,代理)
Nov 28 Javascript
jQuery实现三级菜单的代码
May 09 Javascript
JavaScript基于扩展String实现替换字符串中index处字符的方法
Jun 13 Javascript
浅谈pc端rem字体设置的问题
Aug 03 Javascript
详解JavaScript中的六种错误类型
Sep 21 Javascript
Vue不能检测到Object/Array更新的情况的解决
Jun 26 Javascript
原生JS forEach()和map()遍历的区别、兼容写法及jQuery $.each、$.map遍历操作
Feb 27 jQuery
从0到1构建vueSSR项目之路由的构建
Mar 07 Javascript
解决qrcode.js生成二维码时必须定义一个空div的问题
Jul 09 Javascript
vue实现移动端项目多行文本溢出省略
Jul 29 Javascript
ant design 日期格式化的实现
Oct 27 #Javascript
基于ant design日期控件使用_仅月份的操作
Oct 27 #Javascript
ant-design-vue 时间选择器赋值默认时间的操作
Oct 27 #Javascript
ant design vue中日期选择框混合时间选择器的用法说明
Oct 27 #Javascript
vue-cli3配置favicon.ico和title的流程
Oct 27 #Javascript
Electron+vue从零开始打造一个本地播放器的方法示例
Oct 27 #Javascript
解决vue数据不实时更新的问题(数据更改了,但数据不实时更新)
Oct 27 #Javascript
You might like
回答PHPCHINA上的几个问题:URL映射
2007/02/14 PHP
php中取得URL的根域名的代码
2011/03/23 PHP
php统计文件大小,以GB、MB、KB、B输出
2011/05/29 PHP
PHP删除数组中的特定元素的代码
2012/06/28 PHP
PHP递归调用的小技巧讲解
2013/02/19 PHP
FormValidate 表单验证功能代码更新并提供下载
2008/08/23 Javascript
javascript 进阶篇2 CSS XML学习
2012/03/14 Javascript
JavaScript高级程序设计(第3版)学习笔记6 初识js对象
2012/10/11 Javascript
网页加载时页面显示进度条加载完成之后显示网页内容
2012/12/23 Javascript
jquery控制背景音乐开关与自动播放提示音的方法
2015/02/06 Javascript
socket.io实现在线群聊功能
2017/04/07 Javascript
详解react-webpack2-热模块替换[HMR]
2017/08/03 Javascript
关于Vue.nextTick()的正确使用方法浅析
2017/08/25 Javascript
javascript数组拍平方法总结
2018/01/20 Javascript
如何让node运行es6模块文件及其原理详解
2018/12/11 Javascript
nuxt中使用路由守卫的方法步骤
2019/01/27 Javascript
echarts饼图各个板块之间的空隙如何实现
2020/12/01 Javascript
[44:50]DOTA2上海特级锦标赛B组小组赛#2 VG VS Fnatic第二局
2016/02/26 DOTA
python3使用urllib示例取googletranslate(谷歌翻译)
2014/01/23 Python
5种Python单例模式的实现方式
2016/01/14 Python
Sanic框架配置操作分析
2018/07/17 Python
python3通过selenium爬虫获取到dj商品的实例代码
2019/04/25 Python
解决pyPdf和pyPdf2在合并pdf时出现异常的问题
2020/04/03 Python
html5+css3气泡组件的实现
2014/11/21 HTML / CSS
idealfit英国:世界领先的女性健身用品和运动衣物品牌
2017/11/25 全球购物
事业单位个人应聘自荐信
2013/09/21 职场文书
创业计划书六个要素
2013/12/26 职场文书
人力资源作业细则
2014/03/03 职场文书
2014年入党积极分子党课学习心得体会模板
2014/04/03 职场文书
全运会口号
2014/06/20 职场文书
护士个人年终总结
2015/02/13 职场文书
岗位职责范本大全
2015/02/26 职场文书
甲午大海战观后感
2015/06/02 职场文书
2017春节晚会开幕词
2016/03/03 职场文书
Node与Python 双向通信的实现代码
2021/07/16 Javascript
Go结合Gin导出Mysql数据到Excel表格
2022/08/05 Golang