框架技术Vue ---- Element plus结合综合案例: 用户列表管理
Vue框架内容管理vue-cli创建项目梳理vue3项目的目录vue2中使用路由模块vue2中使用axios组件库vue组件库和bootstrap的区别Element UI按需引入==vue-cli打包的项目,创建vue.config.js,进行配置==拦截器请求拦截器Token认证请求拦截器 -- Loading效果Proxy跨域代理配置proxy代理Proxy代理和baseURL结合问题综合列
Vue框架
内容管理
Vue3组件库 ---- vue-cli、axios拦截器、proxy跨域代理
前面已经分享了路由的基础部分,路由就是组件和hash地址之间的对应关系,在SPA程序中,可以使用嵌套路由实现组件的嵌套,并且通过编程式导航实现组件的切换,router重要的就是router-link和router-view两个标签,和router.js中配置路由规则
接下来就是介绍vue-cli和proxy等,这部分结束之后,vue3的大部分就介绍完了,零碎的只是等写项目的时候补充;至于vue框架的深入 ---- 😀 暂时没有这个打算,因为深入的是SSM和Boot和SQL;前端只要会用即可
vue-cli
vue-cli就是vue脚手架,是vue官方提供的,快速生成vue工程化项目的工具,直接使用,基于webpack,功能丰富并且易于扩展,支持创建vue2和vue3的项目 ----- 这样就不需要像之前分析webpack那样从一个空白项目,配置config,配置locator等一系列操作
之前分享ES6的时候就已经安装了这个脚手架了,npm i -g @cli/vue
PS C:\Windows\system32> vue -V
@vue/cli 4.5.15
运行-V命令显示就说明安装成功
增加powerShell执行权限,运行vue脚本
因为普通窗口没有执行权限,所以不能执行vue命令和npm命令;这个时候首先
- 以管理员身份运行PowerShell
- 执行
set-ExecutionPolicy RemoteSigned
同时键入Y
PS C:\Windows\system32> set-ExecutionPolicy RemoteSigned
执行策略更改
执行策略可帮助你防止执行不信任的脚本。更改执行策略可能会产生安全风险,如 https:/go.microsoft.com/fwlink/?LinkID=135170
中的 about_Execution_Policies 帮助主题所述。是否要更改执行策略?
[Y] 是(Y) [A] 全是(A) [N] 否(N) [L] 全否(L) [S] 暂停(S) [?] 帮助 (默认值为“N”): Y
HbuilderX的终端增加管理员权限
这个很easy,直接点击属性,选择以管理员身份运行程序即可
创建项目
之前基于Vite创建spa的时候,运行的是npm init vite-app XXX
; vue-cli提供了创建项目的两种方式:
- 基于命令行创建
vue create XXX
就可以创建【标准脚手架,命令头都是vue,之前的VIte是npm】
在终端上运行命令的时候,是交互式命令,需要对一些选项进行选择;
vue create vuecli-demo
Vue CLI v4.5.15
┌──────────────────────────────────────────┐
│ │
│ New version available 4.5.15 → 5.0.3 │
│ Run npm i -g @vue/cli to update! │
│ │
└──────────────────────────────────────────┘
? Please pick a preset: (Use arrow keys) 请选择预设,使用键值
> Default ([Vue 2] babel, eslint) 【默认预设:创建vue2项目】
Default (Vue 3) ([Vue 3] babel, eslint) 【默认预设:创建vue3项目】
Manually select features 手动选择功能【预设
这里就选择手动选择功能【其他随意】
------------------------------------------------------------
? Please pick a preset: Manually select features
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection) 空格为选择,a为全选,i为反选,取消选择
>(*) Choose Vue version
(*) Babel
( ) TypeScript
( ) Progressive Web App (PWA) Support
( ) Router
( ) Vuex
( ) CSS Pre-processors
(*) Linter / Formatter
( ) Unit Testing
( ) E2E Testing
这里选择version/babel/Css即可
---------------------------------------
接下里选择版本3.x,less
--------------------------------------
接下来选择存储插件的配置信息
? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
> In dedicated config files 将babel等插件存储在单独的文件中
In package.json 放在包管理文件中
这里建议分开,package就只放依赖包
----------------------------------------
$ cd vuecli-demo
$ npm run serve
- 基于可视化界面创建
vue ui
----- 这个在之前就演示过了,不再赘述;提醒一下【1.预设中选择手动配置项目; 2.在功能页面勾选安装的功能(choose Vue Version 、 Babel、 CSS预设器,使用配置文件】
其实vue ui 本质上就是通过可视化的面板采集用户的配置信息,在后台基于命令行的方式自动初始化项目
运行依赖和开发依赖
运行依赖就是运行的生产环境时依赖的包,简单说就是项目发布后需要依赖的包: 安装的时候是npm i XX -S
显然,vue-router和axios就是运行的依赖
开发依赖是开发的时候需要使用包,一般上线之后并不需要,安装的时候npm i XX -D
之前安装的less等都是开发依赖
这个概念和后端的Maven的类似,比如provied就是生产时不需要的,比如servlet和jsp包
梳理vue3项目的目录
这里简单截图,可以看到和之前的SPA项目还是有所不同,这里的index.html是放在public文件夹下面,不是SPA; main.js是项目的入口文件,.gitgnore是Git的配置文件,babel…是babel的配置文件,package.json包管理文件 ; APP.vue是根组件,这个和之前是相同的
vue2中使用路由模块
- 在src目录下创建router-> index.js路由模块
//导入vueRouter,导入需要创建的路由的组件
import vue from 'vue'
import VueRouter from 'vue-router'
vue.use(VueRouter) // 嗲用vue.use(),将Router全局挂载,vue2中不需要再main.js中配置
const router = new VueRouter({ //vue2中都喜欢使用new的方式,3中是按需导入CreateRouter方法
routes:[
.....
]
})
export default router
在vue2项目中,在main.js中导入index.js,并且将router对象挂载到vue对象中
import Vue from 'vue'
import App from './App.vue'
//导入路由模块
import router from './router'
Vue.config.productionTip = false
const vue2_app = new Vue({
render: h => h(app),
//挂载路由模块
//router: router
router,
})
vue2_app.mout('#app')
其他地方和vue3都是相同的,就不再赘述
vue2中使用axios
vue2中导入anxios相同,唯一不同的就是挂载不是vue3的globalProperties; 而是Vue.prototype.$ajax = axios
Vue2中使用的都是Vue的方式,把每一个组件都看作的Vue的原型链
组件库
组件库和java的类库和其他的jackson等包都是开发者将自己封装的代码发布;在实际开发中,前端开发者将自己封装的.vue组件整理、打包、发布为npm的包,其他人就可以下载和使用,
现成的组件,就是vue组件库
vue组件库和bootstrap的区别
bootstrap只是提供了纯粹的原材料(css样式,HTML结构和JS特性),需要programmer进一步的组装和改造;
vue组件库遵循了Vue的语法,高度定制的现成组件,即拿即用【用现成的…】
Element UI
一个 Vue 3 UI 框架 | Element Plus (gitee.io)
Element UI是XXX开源的一套PC端vue组件库,支持在vue2和vue3项目中使用:vue2使用Element即可,vue3使用Element Plus
- 在项目中安装element-plus ui
npm i element-plus -S
"element-plus": "^2.1.4",
- 引入element-plus
programmer可以一次性完整引入所有的element-ui组件,或者按需引入需要用到的element-ui组件, 完整引入虽然操作简单,但是引入不需要的组件,不建议
//在main.js中引入element-plus
import ElementPlus from 'element-plus'
//导入element ui的组件的样式
import 'element-plus/dist/index.css'
//把ElementUI组测为vue的插件,就可以在项目中每一个组件中使用Element组件
app.use(ElementPlus) //这里和之前的router类似
这样就可以在每一个组件中使用,使用方式就是和之前的bootstrap类似,直接去复制DOM结构到需要用到的地方即可
<template>
<el-form :model="form" label-width="120px">
<el-form-item label="Activity name">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="Activity zone">
<el-select v-model="form.region" placeholder="please select your zone">
<el-option label="Zone one" value="shanghai" />
<el-option label="Zone two" value="beijing" />
</el-select>
</el-form-item>
<el-form-item label="Activity time">
<el-col :span="11">
<el-date-picker
v-model="form.date1"
type="date"
placeholder="Pick a date"
style="width: 100%"
/>
</el-col>
<el-col :span="2" class="text-center">
<span class="text-gray-500">-</span>
</el-col>
<el-col :span="11">
<el-time-picker
v-model="form.date2"
placeholder="Pick a time"
style="width: 100%"
/>
</el-col>
</el-form-item>
<el-form-item label="Instant delivery">
<el-switch v-model="form.delivery" />
</el-form-item>
<el-form-item label="Activity type">
<el-checkbox-group v-model="form.type">
<el-checkbox label="Online activities" name="type" />
<el-checkbox label="Promotion activities" name="type" />
<el-checkbox label="Offline activities" name="type" />
<el-checkbox label="Simple brand exposure" name="type" />
</el-checkbox-group>
</el-form-item>
<el-form-item label="Resources">
<el-radio-group v-model="form.resource">
<el-radio label="Sponsor" />
<el-radio label="Venue" />
</el-radio-group>
</el-form-item>
<el-form-item label="Activity form">
<el-input v-model="form.desc" type="textarea" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">Create</el-button>
<el-button>Cancel</el-button>
</el-form-item>
</el-form>
</template>
<script lang="ts" setup>
import { reactive } from 'vue'
// do not use same name with ref
const form = reactive({
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: '',
})
const onSubmit = () => {
console.log('submit!')
}
</script>
----------这里就复制了一个表单的template的部分----------
样式都在index.css中
按需引入操作复杂,但是只是引入需要用到的组件,优化项目体积
按需引入
按需引入需要借助unplugin-vue-component unplugin-auto-import
插件来实现
- 运行
npm install -D unplugin-vue-components unplugin-auto-import
安装这个插件 - 修改项目根目录的webpack.conofig.js配置文件【没有的可以看下面】
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
module.exports = {
// ...
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
}
vue-cli打包的项目,创建vue.config.js,进行配置
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const {ElementPlusResolver} = require('unplugin-vue-components/resolvers')
module.exports ={
configureWebpack: {
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
]
}
}
可以看到和上面的区别就是,要加上configureWebpack属性,这里博主踩坑了很久😢;
这样就可以按需自动导入了;不需要再去main.js中配置,就使用什么DOM,就会自动导入组件,不需要任何操作;【我们使用element的标签时,无需再使用import对组件进行导入】
比如使用
<el-button>test</el-button>
就会自动导入Button组件,不需要再import;但是需要在main.js中引入EL的样式
import 'element-plus/dist/index.css'
拦截器
拦截器interceptors会在每一次发起ajax请求和得到响应的时候自动触发
拦截器就是分为请求拦截器和响应拦截器;拦截器主要应用为: Token身份认证,Loading效果,
请求拦截器
通过axios.interceptors.request.use(成功的cb,失败的cb) 配置请求拦截器
axios.interceptors.request.use(function(config){
console.log('拦截')
//成功的回调
return config //这里必须return这个config对象,不然会报错,请求可能异常
},function(error){
//失败的回调,可以省略
// return Promise.reject(error)
})
Token认证
可以使用请求拦截器进行token认证
axios.interceptors.request.use(config => {
//为当前请求配置Token
config.headers.Authorization = 'Beaere xxx'
return config //这是固定写法,一定要return
})
config中包含本次请求得所有的信息,比如请求头header等
如果打印config,可以发现
{transitional: {…}, transformRequest: Array(1), transformResponse: Array(1), timeout: 0, adapter: ƒ, …}adapter: ƒ xhrAdapter(config)baseURL: "https://www.escook.cn/api"data: undefinedheaders: Accept: "application/json, text/plain, */*"Authorization: "Barer xxx"[[Prototype]]: ObjectmaxBodyLength: -1maxContentLength: -1method: "get"timeout: 0transformRequest: [ƒ]transformResponse: [ƒ]transitional: {silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false}url: "/cart"validateStatus: ƒ validateStatus(status)xsrfCookieName: "XSRF-TOKEN"xsrfHeaderName: "X-XSRF-TOKEN"[[Prototype]]: Object
App.vue?3dfd:18 {status: 200, message: '获取购物车列表数据成功!', list: Array(10)}
{transitional: {…}, transformRequest: Array(1), transformResponse: Array(1), timeout: 0, adapter: ƒ, …}
adapter: ƒ xhrAdapter(config)
baseURL: "https://escook.cn/api"
data: undefined
headers:
Accept: "application/json, text/plain, */*"
Authorization: "Beaere xxx"
这里说明拦截器拦截成功,将请求的headers中的Authorization成功修改;这里一定要将请求的信息对象config return,不然请求失败
请求拦截器 – Loading效果
借助于element-plus的Loading效果组件,就可以实现Loading的效果展示
直接导入ElLoading,通过service方法创建实例,就可以显示Loading效果; 但是只是配置请求拦截器是不行的,不然Loading效果一直显示,需要配置响应拦截器来关闭Loading效果
import { createApp } from 'vue'
import App from './App.vue'
import axios from "axios"
//完整引入Element
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import { ElLoading } from 'element-plus'
const app = createApp(App)
app.use(ElementPlus)
axios.defaults.baseURL = 'https://www.escook.cn/api'
// axios.interceptors.request.use(config => {
// config.headers.Authorization = 'Barer xxx'
// console.log(config)
// return config
// })
//声明变量表示Loading组件的实例对象
let loadingInstance = null
axios.interceptors.request.use(req => {
//使用Loading组件的service()方法,创建Loading的实例,全屏展示Loading效果
loadingInstance = ElLoading.service({fullscreen: true})
console.log(req)
return req
})
axios.interceptors.response.use(resp => {
//使用实例对象关闭效果
console.log(resp)
loadingInstance.close()
return resp
})
app.config.globalProperties.$ajax = axios
app.mount('#app')
这样就成功进行了Loading效果的展示
Proxy跨域代理
假设vue项目地址: http://localhost:8080/; Api接口的地址https://www.escook.cn/api/users;由于当前API没有开启CORS跨域资源共享,所以默认情况下,上面的接口不能请求成功
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GhDLNXkh-1647960595405)(C:\Users\OMEY-PC\Desktop\proxy.png)]
像这样不能进行资源共享,如果开发过程中,后端开发人员没有开启CORS,那么前端岂不是凉凉?,不是的,可以通过代理解决接口的跨域问题:
通过vue-cli创建的项目,都可以使用代理proxy
实现的步骤:
- 将axios的请求根路径设置为vue项目的运行地址【接口请求不再跨域】
- vue项目发现请求的接口不存在,将请求交给proxy代理
- 代理把请求的根路径变为devServer.proxy的属性的只,发起真正的数据请求【相当于联网访问】
- 代理将请求到的数据,转发给axios
比如,项目所在的直接发起请求
const {data:res} = await this.$ajax.get('/api/cart')
但是当前的位置不存在api接口,那么就会请求失败,存在跨域问题: GET http://localhost:8081/api/cart 404 (Not Found)
配置proxy代理
- 在项目根目录下创建vue.config.js的配置文件,声明配置
module.exports = {
devServer: {
//当前项目会将开发阶段的请求代理到https://www.escook.cn
proxy: 'https://www.escook.cn',
}
}
⚠: devServer.proxy的代理功能,只是在开发调试阶段生效;项目上线发布,仍然需要使用API接口的服务器开启CORS跨域资源共享 ----- 也就是后端设置:允许所有域名的请求访问
在SpringBoot进行配置【后面就会上Boot】
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") //设置所有的请求可以进行跨域
.allowedOrigins("http://localhost:8080") //允许跨域的ip
.allowedMethods("*") //请求的方法 可以不设置 有默认的
.allowedHeaders("*"); //请求头 可以不设置 有默认的
}
}
Proxy代理和baseURL结合问题
之前博主一直按照标准配置proxy代理,可是一直都是跨域,network部分发起的请求一直都是本机;所以emmm…了很久;后面发现是因为将axios的baseURL设置了全路径的相对路径 : https://localhost:3000; 所以请求是直接和baseURL进行结合;发现访问不到,走proxy;直接拼接;报错
删除baseURL之后,会自动按照proxy的地址为相对路径,然后组成绝对路径就可以访问到
而按照网络上80%以上的说法,配置proxy代理是这样的:
proxy: {
'/api': {
target: 'XXXX', //代理的目标的路径
changeOrigin: true, //是否跨域
ws: true,
pathRewrite: { //路径重写,将拼接的路径的/api去除
'^/api': ''
}
}
}
这里的意思就是 :将发起请求的路径,比如/api/cart; 中的/api 替换为target的路径, 并且去掉api; 这样就形成了XXXX/cart
如果需要在main.js中的axios配置baseURL ; 可以简单配置 为 baseURL = ‘/api’
axios.defaults.baseURL = '/api'
const {data:res} = await this.$ajax.get('/cart')
生产环境中api请求接口baseURL配置全路径
在开发环境中使用proxy跨域代理,所以baseURL,设置为/api即可; 如果绝对路径没有api,rewirte去掉即可; 在生产环境中,可以将axios的baseURL设置 — 但是还是需要使用ngix等来解决跨域问题
axios.defaults.baseURL = 'https://www.escook.cn/api'
这样就可以成功访问 ---- 所以baseURL要区分开发环境和生产环境
这样拼接之后为/api/cart ----> 本地按照前台路径发现访问不到,进行跨域代理;拼接proxy的target
; 所以按照我片面的推测; 之前的写法一直报错就是因为进行了错误拼接; 之前的baseURL为https://localhost:3000; 拼接形成https://escook.cnhttps://loaclhost:3000/api/cart 所以还是报错
综合列表案例
这里和之前的列表差不多,只是这里使用的是组件库
初始化项目
这里就还是使用上面的demo项目,因为没有什么污染,创建步骤见上👆
删除本来的Helloweorld组件,配置vue.config.js,设置devServer
module.exports ={
devServer: {
//修改dev期间的端口号
port: 8080,
//自动打开浏览器
open:true,
},
接下来就是初始化路由了: 这里就不用vue2的路由创建方式了:router目录创建index.js; 直接使用vue3的格式
import {createRouter,createWebHashHistory} from "vue-router"
const router = createRouter({
history: createWebHashHistory(),
routes: [
]
})
export default router
------main.js中导入-------------
app.use(router)
渲染用户表格数据
首先就是创建一个UserList.vue组件
routes: [
{path:'/',redirect:'/uses'}
{path:'/users',component: UserList}
]
然后在App中使用router-view占位; 配置axios ,之后发起请求请求用户数据
created() {
this.getUserList()
},
data() {
return {
userList:[],
}
},
methods:{
async getUserList() {
const {data:res} = await this.$ajax.get('/api/users')
//res.status为0表示请求成功
if(res.status !== 0) return console.log('请求用户列表失败')
this.userList = res.data
}
}
但是这里会出现跨域问题,会报错
Access to XMLHttpRequest at 'http://www.escook.cn/api/users' from origin 'http://localhost:8081' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
所以就要配置proxy代理
//axios.defaults.baseURL = 'https://localhost:3000' ---- 会和proxy冲突,会执行baseURL,不走跨域代理
module.exports ={
devServer: {
//修改dev期间的端口号
port: 3000,
//自动打开浏览器
open:true,
proxy: 'https://www.escook.cn'
},
configureWebpack: {
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
]
}
}
这里配置跨域代理之后,就不要乱设置baseURL了!!!!!!!, 😢, 不然就会一直以baseURL为准,然后进行代理,访问报错404详解见上👆
然后就是使用Element-plus进行渲染,就先下载Element-plus包,下载自动按需导入的插件并在vue.config.js中进行配置
npm i Element-plus -S
npm install -D unplugin-vue-components unplugin-auto-import
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const {ElementPlusResolver} = require('unplugin-vue-components/resolvers')
module.exports ={
devServer: {
//修改dev期间的端口号
port: 3000,
//自动打开浏览器
open:true,
proxy: 'https://www.escook.cn'
},
configureWebpack: {
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
]
}
}
然后使用Element-plues的表格组件进行渲染即可
<template>
<div>
<!-- 用户的表格 stripe属性就可以设置为隔行变色 border属性可以设置边框-->
<el-table :data="userList" stripe border>
<!-- 加上type= index就可以自动渲染为索引列 -->
<el-table-column type="index" label="编号" prop="id"></el-table-column>
<el-table-column label="年龄" prop="age"></el-table-column>
<el-table-column label="姓名" prop="name"></el-table-column>
<el-table-column label="职位" prop="position"></el-table-column>
<el-table-column label="入职时间" prop="addtime"></el-table-column>
</el-table>
</div>
</template>
处理时间格式
这里的时间格式可以通过插槽来处理时间格式; el-table-coloum在封装时有一个默认插槽,用户可以填充插槽来规定该列内容的显示格式
<el-table-column label="入职时间">
<!-- 通过 slot 可以获取到 row, column, $index 和 store(table 内部的状态管理)的数据 -->
<template #default='scope'>
<!-- 填充到默认插槽 --- 列的内容 -->
{{formDate(scope.row.addtime)}}
</template>
</el-table-column>
vue3不再使用过滤器,直接使用方法调用来替代,所以直接在methods中声明方法
formDate(date1) {
const date = new Date(date1) //先转为Date对象,才能使用方法
let y = date.getFullYear()
let m = this.padZero(date.getUTCMonth() + 1)
let d = this.padZero(date.getDate())
let hh = this.padZero(date.getHours())
let mm = this.padZero(date.getMinutes())
let ss = this.padZero(date.getMilliseconds())
return y + "-" + m + "-" + d + " " + hh + ":" + mm + ":" + ss
},
padZero(n) { //补0函数
return n > 9 ? n : '0' + n
},
这里的补0函数,是属于组件的,和java中的实例方法一样,需要使用对象调用,不能直接使用
实现添加、删除用户
<el-table-column label="操作">
<template #default>
<a href="#">详情</a>
<a href="#">删除</a>
</template>
</el-table-column>
这里一定要指定插槽的位置,就是#default,不然template中的内容不会渲染到表格中
添加用户
这里需要点击按钮,弹出对话框,对话框还是使用element-plus中的Dialog组件来进行操作
这里直接在官网上寻找即可,dialog对话框组件,将其中的span标签替换为一个表单el-form
<!-- 添加用户的表单 model属性绑定对象-->
<el-form :model ='form'>
<el-form-item label="姓名" label-width = 80px>
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="年龄" label-width = 80px>
<el-input v-model="form.age" />
</el-form-item>
<el-form-item label="职位" label-width = 80px>
<el-input v-model="form.position" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">Cancel</el-button>
<el-button type="primary" @click="dialogVisible = false"
>Confirm</el-button
>
</span>
</template>
</el-dialog>
并且该组件还提供了表单验证的功能,直接在rules中进行绑定即可【validator 验证器,之前的props验证就使用进行自定义验证】
const rules = reactive({
pass: [{ validator: validatePass, trigger: 'blur' }],
checkPass: [{ validator: validatePass2, trigger: 'blur' }],
age: [{ validator: checkAge, trigger: 'blur' }],
})
这里的pass、checkPass、age就是表单项,trigger是触发时机,message就是输入不正确之后的提示信息;还有type,required,min,max等就是类型,是否必要,最小长度,最大长度; 在el-table中通过rules绑定rules;并且在item项中使用prop指定校验规则
<el-form :model ='form' :rules = 'formRules'>
<el-form-item label="姓名" label-width = 80px prop = 'name'> prop的名称字段的名称必须一致
//表单的验证规则对象
formRules:{
name: [ //required必填之后,表单项前面就有一个*
{required:true,message:'姓名是必填项',trigger:'blur'},
{min:3,max:5,message:'长度是3到5个字符',trigger:'blur'}
],
age:[
{required:true,message:'年龄是必填项',trigger:'blur'},
],
position:[
{required:true,message:'职位是必填项',trigger:'blur'},
{min:1,max:10,message:'长度是1到10个字符',trigger:'blur'}
]
}
对于自定义验证规则,就直接通过validator指定验证的函数,声明函数是在data中通过箭头函数复制的方式, 然后指明触发的时机就可
data() {
//声明校验年龄的函数 rule是规则,value是待校验的值,cb是回调函数
//直接调用cb代表验证通过,new Error代表失败
let checkAge = (rule,value,cb) => {
if(!Number.isInteger(value)) {
return cb(new Error('请填写整数!')) //通过回调函数返回错误消息
}
if(value > 100 || value < 1) {
return cb(new Error('年龄必须在1到100之间'))
}
//都满足,验证通过,直接回调
cb()
}
return {
userList:[],
age:[
{required:true,message:'年龄是必填项',trigger:'blur'},
{validator:checkAge,trigger:'blur'}
],
对话框dailog关闭时重置
这个时候就需要监听关闭的事件,直接为el-dialog添加close事件监听
@close = 'onDialogClosed'
//使用提供的form对象的resetFields方法就可以重置
<el-form :model ='form' :rules = 'formRules' ref="myAddFrom">
onDialogClosed() {
//重置表单,直接调用官网提供的resetFields就可以重置
this.$refs.myAddFrom.resetFields()
}
表单预验证
在点击确定按钮的时候,不应该直接发起ajax请求,而是要先判断数据是否合法,并且发起post请求,成功后重新获取数据
//进行表单预验证
onAddNewUser() {
//使用表单对象的validate方法,传递一个cb函数,参数vlaid为false就是验证失败
this.$refs.myAddFrom.validate(async (valid) => {
//valid代表之前的验证结果,成功就是true
if(!valid) return
//正确的就正常发起ajax,get就只是路径,post还需要在第二个参数传递数据,这里就直接是form对象
const {data:res} = await this.$ajax.post('/users',this.form)
// console.log(res) 这里的res就是ajax发起的Promise的结果,status为0代表成功
if(res.status !== 0) return console.log('添加失败')
console.log('添加成功')
this.dialogVisible = false
//刷新用户列表
this.getUserList()
})
}
使用message组件优化提示
Element-Plus提供了消息提示,有success/warning/info/error几种提示,可以直接通过原型对象调用$message.success(‘具体消息即可’) 每个组件都挂载,所以直接通过this即可访问
if(res.status !== 0) return this.$message.error('添加失败')
this.$message.success('添加成功')
但是如果没有全局导入,只是按需导入,那么久直接导入ELMessage,然后使用这个对象的success和error方法即可
import { ElMessage } from 'element-plus'
if(res.status !== 0) return ElMessage.error('添加失败')
ElMessage.success('添加成功')
删除用户前给提示 MessageBox弹框组件
<a href="#" @click.prevent="onRemoveUser">删除</a>
import { ElMessageBox } from 'element-plus'
//删除用户
async onRemoveUser() {
const confirmResult = await ElMessageBox.confirm('此操作将永久删除用户,是否继续?','提示',{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).catch(err => err)
if(confirmResult !== 'confirm') return ElMessage.info('取消了删除')
//确认删除
ElMessage.success('删除成功')
}
如果全局引入,那么使用this.$confirm来代替ELMessageBox
这里要删除,一定要获取id,所以通过作用域插槽【默认插槽可以简写 v-slot=‘scope’】结构复制row.id,传入删除, 请求地址为/users/:id 请求类型为delete,【除了get,post】
async onRemoveUser(id) {
const confirmResult = await ElMessageBox.confirm('此操作将永久删除用户,是否继续?','提示',{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).catch(err => err)
if(confirmResult !== 'confirm') return ElMessage.info('取消了删除')
//确认删除
const {data:res} = this.$ajax.delete('/users/' + id)
if(res.status !== 0) return ElMessage.error('删除失败')
ElMessage.success('删除成功')
//刷新列表
this.getUserList()
}
通过路由跳转详情
这里使用router-link来进行路由
<router-link :to="'/users' + row.id">详情</router-link>
{path:'/users/:id',component:UserDetail,props:true}
<template>
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>用户详情</span>
<el-button class="button" type="text">返回</el-button>
</div>
</template>
其他的琐碎的东西不再赘述,这里展示关键组件UserList
<template>
<div>
<!-- 添加按钮 -->
<el-button type = 'primary' @click = 'dialogVisible = true'>添加新用户</el-button>
<!-- 用户的表格 stripe属性就可以设置为隔行变色 border属性可以设置边框-->
<el-table :data="userList" stripe border>
<!-- 加上type= index就可以自动渲染为索引列 -->
<el-table-column type="index" label="编号" prop="id"></el-table-column>
<el-table-column label="姓名" prop="name"></el-table-column>
<el-table-column label="年龄" prop="age"></el-table-column>
<el-table-column label="职位" prop="position"></el-table-column>
<el-table-column label="入职时间">
<!-- 通过 slot 可以获取到 row, column, $index 和 store(table 内部的状态管理)的数据 -->
<template #default='scope'>
<!-- 填充到默认插槽 --- 列的内容 -->
{{formDate(scope.row.addtime)}}
</template>
</el-table-column>
<el-table-column label="操作">
<template #default='{row}'>
<router-link :to="'/users/' + row.id">详情</router-link>
<a href="#" @click.prevent="onRemoveUser(row.id)">删除</a>
</template>
</el-table-column>
</el-table>
<!-- 对话框 -->
<el-dialog
v-model="dialogVisible"
title="添加新用户"
width="50%"
@close = 'onDialogClosed'
>
<!-- 添加用户的表单 model属性绑定对象-->
<el-form :model ='form' :rules = 'formRules' ref="myAddFrom">
<el-form-item label="姓名" label-width = 80px prop = 'name'>
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="年龄" label-width = 80px prop = 'age'>
<el-input v-model.number="form.age" />
</el-form-item>
<el-form-item label="职位" label-width = 80px prop = 'position'>
<el-input v-model="form.position" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="onAddNewUser">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script>
import { ElMessage } from 'element-plus'
import { ElMessageBox } from 'element-plus'
export default {
name:'UserList',
created() {
this.getUserList()
},
data() {
//声明校验年龄的函数 rule是规则,value是待校验的值,cb是回调函数
//直接调用cb代表验证通过,new Error代表失败
let checkAge = (rule,value,cb) => {
if(!Number.isInteger(value)) {
return cb(new Error('请填写整数!')) //通过回调函数返回错误消息
}
if(value > 100 || value < 1) {
return cb(new Error('年龄必须在1到100之间'))
}
//都满足,验证通过,直接回调
cb()
}
return {
userList:[],
dialogVisible: false, //控制添加对话框显示
form: {//需要采集的信息
name:'',
age: '',
position: '',
},
//表单的验证规则对象
formRules:{
name: [ //required必填之后,表单项前面就有一个*
{required:true,message:'姓名是必填项',trigger:'blur'},
{min:3,max:5,message:'长度是3到5个字符',trigger:'blur'}
],
age:[
{required:true,message:'年龄是必填项',trigger:'blur'},
{validator:checkAge,trigger:'blur'}
],
position:[
{required:true,message:'职位是必填项',trigger:'blur'},
{min:1,max:10,message:'长度是1到10个字符',trigger:'blur'}
]
}
}
},
methods:{
async getUserList() {
const {data:res} = await this.$ajax.get('/users')
//res.status为0表示请求成功
if(res.status !== 0) return console.log('请求用户列表失败')
this.userList = res.data
},
formDate(date1) {
const date = new Date(date1) //先转为Date对象,才能使用方法
let y = date.getFullYear()
let m = this.padZero(date.getUTCMonth() + 1)
let d = this.padZero(date.getDate())
let hh = this.padZero(date.getHours())
let mm = this.padZero(date.getMinutes())
let ss = this.padZero(date.getMilliseconds())
return y + "-" + m + "-" + d + " " + hh + ":" + mm + ":" + ss
},
padZero(n) { //补0函数
return n > 9 ? n : '0' + n
},
//对话框关闭的处理函数
onDialogClosed() {
//重置表单,直接调用官网提供的resetFields就可以重置
this.$refs.myAddFrom.resetFields()
},
//进行表单预验证
onAddNewUser() {
//使用表单对象的validate方法,传递一个cb函数,参数vlaid为false就是验证失败
this.$refs.myAddFrom.validate(async (valid) => {
//valid代表之前的验证结果,成功就是true
if(!valid) return
//正确的就正常发起ajax,get就只是路径,post还需要在第二个参数传递数据,这里就直接是form对象
const {data:res} = await this.$ajax.post('/users',this.form)
// console.log(res) 这里的res就是ajax发起的Promise的结果,status为0代表成功
if(res.status !== 0) return ElMessage.error('添加失败')
ElMessage.success('添加成功')
this.dialogVisible = false
//刷新用户列表
this.getUserList()
})
},
//删除用户
async onRemoveUser(id) {
const confirmResult = await ElMessageBox.confirm('此操作将永久删除用户,是否继续?','提示',{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).catch(err => err)
if(confirmResult !== 'confirm') return ElMessage.info('取消了删除')
//确认删除
const {data:res} = this.$ajax.delete('/users/' + id)
if(res.status !== 0) return ElMessage.error('删除失败')
ElMessage.success('删除成功')
//刷新列表
this.getUserList()
}
},
}
</script>
<style lang="less" scoped>
.el-table {
margin-top: 15px;
}
</style>
看看页面效果
关于vue3的基本知识就到这里了,后面再补充其他的🎉
更多推荐
所有评论(0)