四、vue+ElementUI开发后台管理模板—方法指令、接口数据

(获取本节完整代码 GitHub/chizijijiadami/vue-elementui-4

0、写在前面

这篇文章主要内容包括:
● 自定义全局过滤器
● 自定义全局表单验证
● 获取接口数据、模拟数据——axios+Mockjs 【关联:axios源码学习到使用】
● 跨域访问数据、服务器打包部署——phpstudy、PHP

1、自定义全局方法

(1)状态值过滤
我们数据库里记录一个表单的状态经常用数字1234等表示,在这里我们可以统一记录过滤显示。
● 新建 src>common>filter>status.js

// 订单状态
export function orderStatusFilters(val) {
    if (Number(val) === 0) {
        return '未付款'
    } else if (Number(val) === 1) {
        return '待发货'
    } else if (Number(val) === 2) {
        return '待收货'
    } else if (Number(val) === 3) {
        return '未评价'
    } else if (Number(val) === 4) {
        return '已完成'
    } else if (Number(val) === 5) {
        return '退款'
    } else if (Number(val) === 6) {
        return '退货退款'
    } else if (Number(val) === -1) {
        return '已取消'
    }
}
// 审批状态
export function approvalStatusFilters(val) {
    if (Number(val) === 0) {
        return '未开始'
    } else if (Number(val) === 1) {
        return '审批中'
    } else if (Number(val) === 2) {
        return '已批准'
    } else if (Number(val) === 3) {
        return '已拒绝'
    }
}

新建 src>common>filter>index.js

// 状态
import * as status from './status'
export default {
  ...status
}

● 使用
修改 main.js

+  // 注册全局filters过滤器
+  import filters from './common/filters'
+  Object.keys(filters).forEach(key => {
+    Vue.filter(key, filters[key])
+  })

修改 src>pages>Index>index.vue

+   <p>{{3|orderStatusFilters}}</p>

看下截图,转换成功。

(2)表单验证
● 新建 src>common>validate>validate.js

/* 邮箱 */
export function validateEmail(email) {
  const re = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/
  if (email.length === 0) {
    return { status: false, msg: '邮箱不能为空!' }
  }
  if (!re.test(email)) {
    return { status: false, msg: '请输入有效的邮箱!' }
  }
  return { status: true }
}
// 验证手机号
export function validateMobile(mobile) {
  if (mobile.length !== 11) {
    return { status: false, msg: '请输入有效的手机号码,需是11位!' }
  }

  var myreg = /^(1[0-9]{10})$/
  if (!myreg.test(mobile)) {
    return { status: false, msg: '请输入有效的手机号码!' }
  }
  return { status: true }
}
// 验证身份证
export function validateIDCard(id) {
  // 1 "验证通过!", 0 //校验不通过
  var format = /^(([1][1-5])|([2][1-3])|([3][1-7])|([4][1-6])|([5][0-4])|([6][1-5])|([7][1])|([8][1-2]))\d{4}(([1][9]\d{2})|([2]\d{3}))(([0][1-9])|([1][0-2]))(([0][1-9])|([1-2][0-9])|([3][0-1]))\d{3}[0-9xX]$/
  // 号码规则校验
  if (!format.test(id)) {
    return { status: false, msg: '身份证号码不合规' }
  }
  // 区位码校验
  // 出生年月日校验   前正则限制起始年份为1900;
  var year = id.substr(6, 4) // 身份证年
  var month = id.substr(10, 2) // 身份证月
  var date = id.substr(12, 2) // 身份证日
  var time = Date.parse(month + '-' + date + '-' + year) // 身份证日期时间戳date
  var nowTime = Date.parse(new Date()) // 当前时间戳
  var dates = new Date(year, month, 0).getDate() // 身份证当月天数
  if (time > nowTime || date > dates) {
    return { status: false, msg: '出生日期不合规' }
  }
  // 校验码判断
  var c = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2] // 系数
  var b = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'] // 校验码对照表
  var idArray = id.split('')
  var sum = 0
  for (var k = 0; k < 17; k++) {
    sum += parseInt(idArray[k]) * parseInt(c[k])
  }
  if (idArray[17].toUpperCase() !== b[sum % 11].toUpperCase()) {
    return { status: false, msg: '身份证校验码不合规' }
  }
  return { status: true, msg: '校验通过' }
}

新建 src>common>validate>regCheck.js

import {
  // 11位手机号
  validateMobile,
  // 邮箱
  validateEmail,
  // 身份证
  validateIDCard
} from './validate'

export const validatorCode = {
  // 非空校验
  checkNotNull(rule, value, callback) {
    if (
      String(value).replace(/^\s+|\s+$/gm, '') === '' ||
      (value instanceof Array && value[0] === '') ||
      value === null ||
      value === undefined
    ) {
      callback(new Error(this.message || (this.name || '内容') + '不能为空!'))
    } else {
      callback()
    }
  },
  // 11位手机号
  checkMobile(rule, value, callback) {
    if (value !== null && value !== '') {
      if (!validateMobile(value).status) {
        callback(new Error(validateMobile(value).msg))
      } else {
        callback()
      }
    } else {
      callback()
    }
  },
  // 邮箱
  checkEmail(rule, value, callback) {
    if (value !== null && value !== '') {
      if (!validateEmail(value).status) {
        callback(new Error(validateMobile(value).msg))
      } else {
        callback()
      }
    } else {
      callback()
    }
  },
  // 身份证号
  checkIdCard(rule, value, callback) {
    if (value !== null && value !== '') {
      if (!validateIDCard(value).status) {
        callback(new Error(validateMobile(value).msg))
      } else {
        callback()
      }
    } else {
      callback()
    }
  },
}

新建 src>common>validate>index.js

import { validatorCode } from './regCheck.js'
export default function install(Vue) {
    Vue.prototype.regCheck = function (item) {
        let rules = []
        let _trigger = item.trigger || 'blur'
        let _required = item.required || false
        let _type = item.type

        if (_required) {
            rules.push({
                required: true,
                validator: validatorCode.checkNotNull.bind(item),
                trigger: _trigger
            })
        }
        if (_type) {
            switch (_type) {
                // 手机校验
                case 'mobile':
                    rules.push({
                        required: _required,
                        validator: validatorCode.checkMobile,
                        trigger: _trigger
                    })
                    break
                // 邮箱校验
                case 'email':
                    rules.push({
                        required: _required,
                        validator: validatorCode.checkEmail,
                        trigger: _trigger
                    })
                    break
                // 身份证校验
                case 'idCard':
                    rules.push({
                        required: _required,
                        validator: validatorCode.checkIdCard,
                        trigger: _trigger
                    })
                    break
                default:
                    rules.push({})
                    break
            }
        }
        return rules
    }
}

● 使用
修改 main.js

+  // 全局校验
+  import Validate from '@/common/validate/index.js'
+  Vue.use(Validate)

修改 src>pages>Index>index.vue

+  <div>
+        <el-form :model="form" ref="form" label-width="100px">
+          <el-form-item
+            prop="mobile"
+            label="手机号码"
+            :rules="regCheck({required:true,type:'mobile',message:'手机号码为必输项'})"
+          >
+            <el-input v-model="form.mobile"></el-input>
+          </el-form-item>
+          <el-form-item
+            prop="email"
+            label="邮箱"
+            :rules="regCheck({required:true,type:'email',name:'邮箱'})"
+          >
+            <el-input v-model="form.email"></el-input>
+          </el-form-item>
+          <el-form-item prop="idCard" label="身份证号" :rules="regCheck({required:true,type:'idCard'})">
+            <el-input v-model="form.idCard"></el-input>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="submitForm('form')">提交</el-button>
+            <el-button @click="resetForm('form')">重置</el-button>
+          </el-form-item>
+        </el-form>
+      </div>



+    methods: {
+      submitForm(formName) {
+        this.$refs[formName].validate(valid => {
+          if (valid) {
+            alert("submit!");
+          } else {
+            console.log("error submit!!");
+            return false;
+          }
+        });
+      },
+      resetForm(formName) {
+        this.$refs[formName].resetFields();
+      },
+  }

看下效果,可以自己改着各种值试一下。
2、获取接口数据、模拟数据—— axiosmockjs

(1) axios 数据请求
● 安装

yarn add axios

● 添加拦截器
新建 common>utils>axiosApi.js

import axios from 'axios'
import ErrorMessage from './errorMessage'
import { MessageBox } from 'element-ui'
var instance = axios.create({
    baseURL: '',
    timeout: 5000
});
// 添加请求拦截器
instance.interceptors.request.use(
    // 在发送请求之前做些什么
    config => {
        config.headers['version'] = '1'
        return config
    },
    error => {
        Promise.reject(error)
    }
);

// 添加响应拦截器
instance.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    if (response.data.status !== 0) {
        return Promise.reject(response)
    } else {
        return Promise.resolve(response)
    }
}, function (error) {
    // 对响应错误做点什么
    if (!error.response) {
        // 服务器请求失败时错误提示
        MessageBox({
            message: `请求超时${ErrorMessage.API_ERROR_LOAD}`,
            showCancelButton: false,
            confirmButtonText: '确定',
            type: 'error',
            callback() { }
        })
    } else {
        let errorStatus = error.response.status
        switch (errorStatus) {
            case 400:
                error.message = ErrorMessage.STATUS_400
                break
            case 401:
                error.message = ErrorMessage.STATUS_401
                break
            case 403:
                error.message = ErrorMessage.STATUS_403
                break
            case 404:
                error.message = ErrorMessage.STATUS_404
                break
            case 408:
                error.message = ErrorMessage.STATUS_408
                break
            case 500:
                error.message = ErrorMessage.STATUS_500
                break
            case 501:
                error.message = ErrorMessage.STATUS_501
                break
            case 502:
                error.message = ErrorMessage.STATUS_502
                break
            case 503:
                error.message = ErrorMessage.STATUS_503
                break
            case 504:
                error.message = ErrorMessage.STATUS_504
                break
            case 505:
                error.message = ErrorMessage.STATUS_505
                break
            default:
        }
        MessageBox({
            message: error.response.config.url + " " + error.message,
            showCancelButton: false,
            confirmButtonText: '确定',
            type: 'error',
            callback() {
                if (errorStatus == 404) {
                    console.log('44444444444');
                }
            }
        })
    }
    return Promise.reject(error);
});
export default function (config) {
    let _config = {
        url: '',
        method: 'get'
    }
    _config = Object.assign(_config, config)
    _config.params = _config.params
        ? _config.filter
            ? _config.filter.request(JSON.parse(JSON.stringify(_config.params)))
            : _config.params
        : ''
    if (_config.method.toLowerCase() != 'get') {
        _config.data = _config.params
        _config.params = {}
    }
    return new Promise((resolve, reject) => {
        return instance(_config)
            .then(response => {
                resolve(_config.filter ? _config.filter.response(response.data) : response.data)
            })
            .catch(error => {
                reject(error)
            })
    })
}

新建 common>utils>errorMassage.js

const ErrorMessage = {
  API_ERROR_LOAD: '服务器无响应!',
  STATUS_400: '请求错误!',
  STATUS_401: '登录超时!',
  STATUS_403: '拒绝访问!',
  STATUS_404: '请求地址出错!',
  STATUS_408: '请求超时!',
  STATUS_500: '服务器内部错误!',
  STATUS_501: '服务未实现!',
  STATUS_502: '网关错误!',
  STATUS_503: '服务不可用!',
  STATUS_504: '网关超时!',
  STATUS_505: 'HTTP版本不受支持!'
}
export default ErrorMessage

● 使用
新建 src>data>api>Index>index.js

import axiosApi from '@/common/utils/axiosApi'
import * as filter from './filter'
export function getList(params) {
    return axiosApi({
        url: '/list',
        method: 'get',
        filter: filter.getList,
        params: params
    })
}
export function getTitle(params) {
    return axiosApi({
        url: '/title',
        method: 'get',
        filter: filter.getTitle,
        params: params
    })
}

新建 src>data>api>Index>filter.js,过滤处理数据

export const getList = {
  request(params) {
    return params
  },
  response(data) {
    return data
  }
}
export const getTitle= {
  request(params) {
    return params
  },
  response(data) {
    return data
  }
}

修改 src>pages>Index>index.vue

+  import * as api from "data/api/Index";
export default {
  name: "IndexIndex",
  data() {
    return {
      form: {
        mobile: "",
        email: "",
        idCard: ""
      }
    };
  },
+    created() {
+      this.getList();
+    },
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate(valid => {
        if (valid) {
          alert("submit!");
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
    resetForm(formName) {
      this.$refs[formName].resetFields();
    },
+      getList() {
+        api.getList().then(res => {
+        console.log(res);
+       });
+      }
  }
}

因为我们这个项目里没有 /list 这个接口,所以报错了,一般前后分离开发是同步进行的,为了方便前端开发,我们就得模拟接口及其返回数据,下面我们用 mockjs 来实现。


(2)mockjs 模拟接口数据

● 安装

yarn add mockjs -D

● 使用
新建 src>data>mock>index.js

const Mock = require("mockjs");
// 使用mockjs模拟数据
let dataList = Mock.mock({
  // 属性 list 的值是一个数组,其中含有 1 到 10 个元素
  "list|1-10": [
    {
      // 属性 id 是一个自增数,起始值为 1,每次增 1
      "id|+1": 1,
      name: "@FIRST",
      creatTime: "@datetime"
    }
  ]
});
Mock.mock("/list", "get", () => {
  return {
    status: 0,
    data: dataList,
    message: "成功"
  };
});

修改 main.js

+  //mockj数据
+  import 'data/mock'

刷新页面,可以看到控制台打印的信息。我们在页面中使用显示一下

修改 src>pages>Index>index.vue

+    <div>
+      <p v-for="item in list" :key="item.id">{{item.name}}</p>
+    </div>

  data() {
    return {
      form: {
        mobile: "",
        email: "",
        idCard: ""
      },
+      list: []
    };
  },

    getList() {
      api.getList().then(res => {
-        console.log(res);
+        this.list=res.data.list
      });
    }

如图:

到这里我们的全局方法指令跟接口数据就结束了,下一篇写完到按钮级别的权限控制这个后台管理模板也结束了。
另外如果你不想用mock数据,可以自己写服务接口,我们前端用nodejs或者php都是挺方便的,nodejs后面会写专门的文章介绍,下面介绍php,这里也同样适用跨域获取第三方接口数据。

3、拓展——结合 phpstudy 使用PHP写接口

phpstudy的安装使用见官网或者参考 一、vue入门基础开发—手把手教你用vue开发 文章最后即第四大点的第(3)部分的拓展。
在这里我们新建一个网站。


在vscode中打开 WWW 文件夹,新建文件 index.php

<?php
$data = array();
$data['status'] = 0;
$data['list'] = array();
$data['list'][0] = ['name' => 'ha'];
$data['list'][1] = ['name' => 'hei'];
exit(json_encode($data));

修改 .env.development

   NODE_ENV = 'development'
   VUE_APP_BASE_API = 'http://192.168.0.1'
+  VUE_APP_CROSS_DOMAIN='http://localhost:6789'

修改 src>data>api>Index>index.js,注意看这里有个注释掉的语句,如果是打包部署到这个新建的网站里就用注释掉的那个语句,因为我们没有配置生产环境里CROSS_DOMAIN。当然,如果你在 .env.produntion 里同样配置了CROSS_DOMAIN,那就还用没注释的这条就好。

+  export function getCrossDomainList(params) {
+      return axiosApi({
+          url: process.env.VUE_APP_CROSS_DOMAIN+"/index.php",
+         //url: (process.env.NODE_ENV === "development" ? process.env.VUE_APP_CROSS_DOMAIN : "") + "/index.php",
+          method: 'get',
+          filter: filter.getCrossDomainList,
+          params: params
+      })
+  }

修改 src>data>api>Index>filter.js,假设这里返回的人名都要大写,我们在这里处理。

+  export const getCrossDomainList = {
+    request(params) {
+      return params
+    },
+    response(data) {
+      for (let i = 0; i < data.list.length; i++) {
+        data.list[i].name = data.list[i].name.toUpperCase()
+      }
+      return data
+    }
+  }

使用,修改 src>pages>Index>index.vue

   created() {
     this.getList();
+    this.getCrossDomainList();
   },

methods:{
......
+    getCrossDomainList() {
+      api.getCrossDomainList().then(res => {
+        console.log(res);
+      });
+    }
}

第三方接口方式
运行一下,控制台里看到报跨域了。


这就需要在服务器配置里修改,phpstudy_pro\Extensions\Apache2.4.39\conf\vhosts 路径下找到我们新建网站的配置文件 ,打开添加允许跨域访问语句。

      Header set Access-Control-Allow-Origin http://localhost:8081
      Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
      Header set Access-Control-Allow-Headers *

添加后保存,重新启动Apache服务器生效,再次刷新页面,获取成功,如下图


打包部署方式
这里不存在跨域问题,但是看到控制台是没有信息输出的,因为我们在第一篇里说过生产环境去console的插件 babel-plugin-transform-remove-console

感谢阅读,,喜欢的话点个赞吧:)更多内容请关注后续文章。

一、vue入门基础开发—手把手教你用vue开发
二、vue+ElementUI开发后台管理模板—布局
三、vue+ElementUI开发后台管理模板—功能、资源、全局组件
五、vue+ElementUI开发后台管理模板—精确到按钮的权限控制

vue3 + vite + ElementPlus开发后台管理模板

vue实践1.1 企业官网——prerender-spa-plugin预渲染

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335