Vue3实战教程(快速入门)
- 前言
- 1.搭建脚手架
- 1.1 创建项目
- 1.2 清除多余文件,创建干净项目
- 1.3 创建登录页面
- 2.创建404页面(引入sass)
- 3.构建登录注册页面(引入element-plus)
- 3.1 实现布局左右切换动画
- 3.2 引入element-plus
- 3.3 使用element-plus表单组件
- 3.4 表单验证
- 4.类型匹配和代码抽离
- 4.1 代码抽离
- 4.2 类型匹配
- 4.2.1 ts文件类型匹配
- 4.2.2 vue文件中的ts类型匹配
- 5.抽离登录组件
- 6. 实现注册表单
- 6.1 创建注册表单ts——存放注册表单及其验证规则
- 6.2 创建注册表单组件
- 6.3 在LoginRegister.vue中引入使用
- 7. 封装axios
- 7.1 下载axios
- 7.2 封装axios
- 7.3 解决跨域问题(配置vue.config.js,设置代理)
- 7.4 使用axios发起请求
- 7.4.1 创建api文件夹,规范使用api(推荐)
- 7.4.2 全局注册axios(不推荐,也没必要)
- 8.总结
前言
本教程通过搭建一个简单项目,帮助读者快速入门Vue3项目实战,掌握Vue3、TS、Element Plus、axios等技术栈。
1.搭建脚手架
vue -V查看vue版本,需要在4.5.1版本之后,即可进行以下操作。
1.1 创建项目
(1)使用命令 vue create vue3-elementplus-demo 创建Vue项目。
(2)进入选项配置,选择 Manually select features,进行手动配置
(3)配置项如下
都选择完毕后,回车,项目即可创建完毕,使用VsCode或者按照提示进入和启动项目
1.2 清除多余文件,创建干净项目
(1)删除以下文件
(2)在views目录下创建Index.vue文件(后面处于方便,又将Index.vue修改成了Home.vue),内容如下:
<template
>
<div
>首页
</div
>
</template
>
<script
>
export default {
name: 'Index'
}
</script
>
<style scoped
></style
>
(3)修改router/index.ts路由文件:
import { createRouter
, createWebHistory
, RouteRecordRaw
} from 'vue-router'
import Home
from '../views/Home.vue'
const routes: Array
<RouteRecordRaw
> = [
{
path: '/',
name: 'Index',
component: () => import('../views/Index.vue')
},
]
const router
= createRouter({
history: createWebHistory(process
.env
.BASE_URL),
routes
})
export default router
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
(4)修改App文件:
<template
>
<div id
="app">
<router
-view
/>
</div
>
</template
>
<style
>
html
,
body
,
#app
{
width: 100%;
height: 100%;
}
</style
>
修改完毕后,查看效果
(5)新建css/resset.css文件(上网搜关键词reset.css就有),并在index.html文件中引入,初始化样式
/**
* Eric Meyer's Reset CSS v2.0 (http://meyerweb.com/eric/tools/css/reset/)
* http://cssreset.com
*/
html
, body
, div
, span
, applet
, object
, iframe
,
h1
, h2
, h3
, h4
, h5
, h6
, p
, blockquote
, pre
,
a
, abbr
, acronym
, address
, big
, cite
, code
,
del
, dfn
, em
, img
, ins
, kbd
, q
, s
, samp
,
small
, strike
, strong
, sub
, sup
, tt
, var,
b
, u
, i
, center
,
dl
, dt
, dd
, ol
, ul
, li
,
fieldset
, form
, label
, legend
,
table
, caption
, tbody
, tfoot
, thead
, tr
, th
, td
,
article
, aside
, canvas
, details
, embed
,
figure
, figcaption
, footer
, header
, hgroup
,
menu
, nav
, output
, ruby
, section
, summary
,
time
, mark
, audio
, video
{
margin: 0;
padding: 0;
border: 0;
font
-size
: 100%;
font: inherit
;
font
-weight
: normal
;
vertical
-align
: baseline
;
}
/* HTML5 display-role reset for older browsers */
article
, aside
, details
, figcaption
, figure
,
footer
, header
, hgroup
, menu
, nav
, section
{
display: block
;
}
ol
, ul
, li
{
list
-style
: none
;
}
blockquote
, q
{
quotes: none
;
}
blockquote:before
, blockquote:after
,
q:before
, q:after
{
content: '';
content: none
;
}
table
{
border
-collapse
: collapse
;
border
-spacing
: 0;
}
/* custom */
a
{
color: #7e8c8d
;
text
-decoration
: none
;
-webkit
-backface
-visibility
: hidden
;
}
::-webkit
-scrollbar
{
width: 5px
;
height: 5px
;
}
::-webkit
-scrollbar
-track
-piece
{
background
-color
: rgba(0, 0, 0, 0.2);
-webkit
-border
-radius
: 6px
;
}
::-webkit
-scrollbar
-thumb
:vertical
{
height: 5px
;
background
-color
: rgba(125, 125, 125, 0.7);
-webkit
-border
-radius
: 6px
;
}
::-webkit
-scrollbar
-thumb
:horizontal
{
width: 5px
;
background
-color
: rgba(125, 125, 125, 0.7);
-webkit
-border
-radius
: 6px
;
}
html
, body
{
width: 100%;
font
-family
: "Arial", "Microsoft YaHei", "黑体", "宋体", "微软雅黑", sans
-serif
;
}
body
{
line
-height
: 1;
-webkit
-text
-size
-adjust
: none
;
-webkit
-tap
-highlight
-color
: rgba(0, 0, 0, 0);
}
html
{
overflow
-y
: scroll
;
}
/*清除浮动*/
.clearfix
:before
,
.clearfix
:after
{
content: " ";
display: inline
-block
;
height: 0;
clear: both
;
visibility: hidden
;
}
.clearfix
{
*zoom
: 1;
}
/*隐藏*/
.dn
{
display: none
;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
1.3 创建登录页面
创建LoginRegister.vue文件:
<template
>
<div
class="container">
<!-- form表单容器
-->
<div
class="form-container">
<div
class="signin-signup">
<!-- 登录
-->
<h1
>登录
</h1
>
<!-- 注册
-->
<h1
>注册
</h1
>
</div
>
</div
>
</div
>
</template
>
<script
>
export default {
name: 'LoginRegister'
}
</script
>
<style scoped
>
.container
{
position: relative
;
width: 100%;
min
-height
: 100vh
;
background
-color
: #fff
;
overflow: hidden
;
}
.form
-container
{
position: absolute
;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.signin
-signup
{
position: relative
;
top: 50%;
left: 75%;
transform: translate(-50%, -50%);
width: 44%;
transition: 1s
0.7s ease
-in-out
;
display: grid
;
grid
-template
-columns
: 1fr
;
z
-index
: 5;
}
</style
>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
在路由中引入
查看效果:
2.创建404页面(引入sass)
2.1 引入sass
(1)查看当前node版本
(2)引入对应版本的node-sass和sass-load
当前已知 node-sass 与 node 版本对应如下:https://github.com/sass/node-sass
node-sass 和 sass-loader 的常见版本对应关系如下:
node-sass | sass-loader |
---|
4.3.0 | 4.1.1 |
4.7.2 | $7.0.3/7.3.1 |
6.0.1 | 10.0.1 |
(3)如果引入出现了问题,基本上就是node版本和sass版本不一致导致。此时需要创建一个新项目,将新项目中的package.json和package-lock.json复制到当前项目中,然后重新 npm i 即可。
2.2 创建404页面
(1)assets下创建img文件夹,加入404.gif
(2)创建404.vue
<template
>
<div
class="not-found">
<img src
="../assets/img/404.gif" alt
="" />
</div
>
</template
>
<script
>
export default {
name: '404'
}
</script
>
<style lang
="scss" scoped
>
.not
-found
{
width: 100%;
height: 100%;
overflow: hidden
;
img
{
width: 100%;
height: 100%;
}
}
</style
>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
(3)router/index.ts中通过正则表达式匹配匹配失败的路由为404页面
3.构建登录注册页面(引入element-plus)
3.1 实现布局左右切换动画
因为本篇文章主要讲解的是Vue3和element-plus的用法,css部分就省略说明,有兴趣的同学可以自行研究。
<template
>
<div
class="container" :class="{ 'sign-up-mode': signUpMode }">
<!-- form表单容器
-->
<div
class="form-container">
<div
class="signin-signup">
<!-- 登录
-->
<h1
>登录
</h1
>
<!-- 注册
-->
<h1
>注册
</h1
>
</div
>
</div
>
<!-- 左右切换动画
-->
<div
class="panels-container">
<div
class="panel left-panel">
<div
class="content">
<h3
>Row
,row
,row your boat
</h3
>
<p
>Gentlely down the stream
</p
>
<button @click
="signUpMode = !signUpMode" class="btn transparent">
注册
</button
>
</div
>
<!-- <img src
="@/assets" alt
=""> -->
</div
>
<div
class="panel right-panel">
<div
class="content">
<h3
>Merrily
,merrily
,merrily
,merrily
,</h3
>
<p
>Life is but a dream
</p
>
<button @click
="signUpMode = !signUpMode" class="btn transparent">
登录
</button
>
</div
>
<!-- <img src
="@/assets" alt
=""> -->
</div
>
</div
>
</div
>
</template
>
<script
>
import { ref
} from 'vue'
export default {
name: 'LoginRegister',
components: {},
// Vue3语法糖
// Vue2是通过data和methods传递数据和方法
// Vue3将data和methods直接耦合在了一起
setup() {
// 登录/注册模式
const signUpMode
= ref(false)
return { signUpMode
}
}
}
</script
>
<style scoped
>
.container
{
position: relative
;
width: 100%;
min
-height
: 100vh
;
background
-color
: #fff
;
overflow: hidden
;
}
.form
-container
{
position: absolute
;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.signin
-signup
{
position: relative
;
top: 50%;
left: 75%;
transform: translate(-50%, -50%);
width: 44%;
transition: 1s
0.7s ease
-in-out
;
display: grid
;
grid
-template
-columns
: 1fr
;
z
-index
: 5;
}
/* 左右切换动画 */
.social
-text
{
padding: 0.7rem
0;
font
-size
: 1rem
;
}
.social
-media
{
display: flex
;
justify
-content
: center
;
}
.social
-icon
{
height: 46px
;
width: 46px
;
display: flex
;
justify
-content
: center
;
align
-items
: center
;
margin: 0 0.45rem
;
color: #
333;
border
-radius
: 50%;
border: 1px solid #
333;
text
-decoration
: none
;
font
-size
: 1.1rem
;
transition: 0.3s
;
}
.social
-icon
:hover
{
color: #4481eb
;
border
-color
: #4481eb
;
}
.btn
{
width: 150px
;
background
-color
: #5995fd
;
border: none
;
outline: none
;
height: 49px
;
border
-radius
: 49px
;
color: #fff
;
text
-transform
: uppercase
;
font
-weight
: 600;
margin: 10px
0;
cursor: pointer
;
transition: 0.5s
;
}
.btn
:hover
{
background
-color
: #4d84e2
;
}
.panels
-container
{
position: absolute
;
height: 100%;
width: 100%;
top: 0;
left: 0;
display: grid
;
grid
-template
-columns
: repeat(2, 1fr
);
}
.container
:before
{
content: '';
position: absolute
;
height: 2000px
;
width: 2000px
;
top: -10%;
right: 48%;
transform: translateY(-50%);
background
-image
: linear
-gradient(-45deg
, #4481eb
0%, #04befe
100%);
transition: 1.8s ease
-in-out
;
border
-radius
: 50%;
z
-index
: 6;
}
.image
{
width: 100%;
transition: transform
1.1s ease
-in-out
;
transition
-delay
: 0.4s
;
}
.panel
{
display: flex
;
flex
-direction
: column
;
align
-items
: flex
-end
;
justify
-content
: space
-around
;
text
-align
: center
;
z
-index
: 6;
}
.left
-panel
{
pointer
-events
: all
;
padding: 3rem
17% 2rem
12%;
}
.right
-panel
{
pointer
-events
: none
;
padding: 3rem
12% 2rem
17%;
}
.panel
.content
{
color: #fff
;
transition: transform
0.9s ease
-in-out
;
transition
-delay
: 0.6s
;
}
.panel h3
{
font
-weight
: 600;
line
-height
: 1;
font
-size
: 1.5rem
;
}
.panel p
{
font
-size
: 0.95rem
;
padding: 0.7rem
0;
}
.btn
.transparent
{
margin: 0;
background: none
;
border: 2px solid #fff
;
width: 130px
;
height: 41px
;
font
-weight
: 600;
font
-size
: 0.8rem
;
}
.right
-panel
.image
,
.right
-panel
.content
{
transform: translateX(800px
);
}
/* ANIMATION */
.container
.sign
-up
-mode
:before
{
transform: translate(100%, -50%);
right: 52%;
}
.container
.sign
-up
-mode
.left
-panel
.image
,
.container
.sign
-up
-mode
.left
-panel
.content
{
transform: translateX(-800px
);
}
.container
.sign
-up
-mode
.signin
-signup
{
left: 25%;
}
.container
.sign
-up
-mode form
.sign
-up
-form
{
opacity: 1;
z
-index
: 2;
}
.container
.sign
-up
-mode form
.sign
-in-form
{
opacity: 0;
z
-index
: 1;
}
.container
.sign
-up
-mode
.right
-panel
.image
,
.container
.sign
-up
-mode
.right
-panel
.content
{
transform: translateX(0%);
}
.container
.sign
-up
-mode
.left
-panel
{
pointer
-events
: none
;
}
.container
.sign
-up
-mode
.right
-panel
{
pointer
-events
: all
;
}
@
media (max-width: 870px) {
.container
{
min
-height
: 800px
;
height: 100vh
;
}
.signin
-signup
{
width: 100%;
top: 95%;
transform: translate(-50%, -100%);
transition: 1s
0.8s ease
-in-out
;
}
.signin
-signup
,
.container
.sign
-up
-mode
.signin
-signup
{
left: 50%;
}
.panels
-container
{
grid
-template
-columns
: 1fr
;
grid
-template
-rows
: 1fr 2fr 1fr
;
}
.panel
{
flex
-direction
: row
;
justify
-content
: space
-around
;
align
-items
: center
;
padding: 2.5rem
8%;
grid
-column
: 1 / 2;
}
.right
-panel
{
grid
-row
: 3 / 4;
}
.left
-panel
{
grid
-row
: 1 / 2;
}
.image
{
width: 200px
;
transition: transform
0.9s ease
-in-out
;
transition
-delay
: 0.6s
;
}
.panel
.content
{
padding
-right
: 15%;
transition: transform
0.9s ease
-in-out
;
transition
-delay
: 0.8s
;
}
.panel h3
{
font
-size
: 1.2rem
;
}
.panel p
{
font
-size
: 0.7rem
;
padding: 0.5rem
0;
}
.btn
.transparent
{
width: 110px
;
height: 35px
;
font
-size
: 0.7rem
;
}
.container
:before
{
width: 1500px
;
height: 1500px
;
transform: translateX(-50%);
left: 30%;
bottom: 68%;
right: initial
;
top: initial
;
transition: 2s ease
-in-out
;
}
.container
.sign
-up
-mode
:before
{
transform: translate(-50%, 100%);
bottom: 32%;
right: initial
;
}
.container
.sign
-up
-mode
.left
-panel
.image
,
.container
.sign
-up
-mode
.left
-panel
.content
{
transform: translateY(-300px
);
}
.container
.sign
-up
-mode
.right
-panel
.image
,
.container
.sign
-up
-mode
.right
-panel
.content
{
transform: translateY(0px
);
}
.right
-panel
.image
,
.right
-panel
.content
{
transform: translateY(300px
);
}
.container
.sign
-up
-mode
.signin
-signup
{
top: 5%;
transform: translate(-50%, 0);
}
}
@
media (max-width: 570px) {
form
{
padding: 0 1.5rem
;
}
.image
{
display: none
;
}
.panel
.content
{
padding: 0.5rem 1rem
;
}
.container
{
padding: 1.5rem
;
}
.container
:before
{
bottom: 72%;
left: 50%;
}
.container
.sign
-up
-mode
:before
{
bottom: 28%;
left: 50%;
}
}
/* 控制login & register显示 */
form
{
padding: 0rem 5rem
;
transition: all
0.2s
0.7s
;
overflow: hidden
;
}
form
.sign
-in-form
{
z
-index
: 2;
}
form
.sign
-up
-form
{
opacity: 0;
z
-index
: 1;
}
/* register */
.loginForm
,
.registerForm
{
margin
-top
: 20px
;
background
-color
: #fff
;
padding: 20px 40px 20px 20px
;
border
-radius
: 5px
;
box
-shadow
: 0px 5px 10px #cccc
;
}
.submit
-btn
{
width: 100%;
}
.tiparea
{
text
-align
: right
;
font
-size
: 12px
;
color: #
333;
width: 100%;
}
.tiparea a
{
color: #409eff
;
}
</style
>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368
- 369
- 370
- 371
- 372
- 373
- 374
- 375
- 376
- 377
- 378
- 379
- 380
- 381
- 382
- 383
- 384
- 385
- 386
- 387
- 388
- 389
- 390
- 391
- 392
- 393
- 394
- 395
- 396
- 397
- 398
- 399
- 400
- 401
- 402
- 403
- 404
- 405
- 406
- 407
- 408
- 409
- 410
- 411
- 412
- 413
- 414
- 415
- 416
- 417
- 418
3.2 引入element-plus
(1)下载element-plus包:
npm i element
-plus
(2)在main.ts中引入
3.3 使用element-plus表单组件
(1)setup中加入登录表单loginUser
setup() {
// 登录/注册模式
const signUpMode
= ref(false)
// 登录表单
const loginUser
= reactive({
email: '',
password: ''
})
return { signUpMode
, loginUser
}
}
(2)使用表单组件
<!-- 登录
-->
<el
-form
:model
="loginUser"
label
-width
="100px"
class="login-form sign-in-form"
>
<el
-form
-item label
="邮箱" prop
="email">
<el
-input v
-model
="loginUser.email" placeholder
="Enter Email..." />
</el
-form
-item
>
<el
-form
-item label
="密码" prop
="password">
<el
-input
v
-model
="loginUser.password"
type
="password"
placeholder
="Enter Password..."
/>
</el
-form
-item
>
<el
-form
-item
>
<el
-button type
="primary" class="submit-btn">提交
</el
-button
>
</el
-form
-item
>
<!-- 找回密码
-->
<el
-form
-item
>
<p
class="tiparea">忘记密码
<a
>立即找回
</a
></p
>
</el
-form
-item
>
</el
-form
>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
3.4 表单验证
(1)表单验证
关键代码:
// 校验规则
const rules
= reactive({
email: [
{
required: true,
type: 'email',
message: 'email格式错误',
trigger: 'blur'
}
],
password: [
{ required: true, message: '密码不得为空', trigger: 'blur' },
{ min: 6, max: 30, message: '密码长度必须在6到30之间', trigger: 'blur' }
]
})
(2)点击提交触发表单验证
关键代码:
<template
>
<div
class="container" :class="{ 'sign-up-mode': signUpMode }">
<!-- form表单容器
-->
<div
class="form-container">
<div
class="signin-signup">
<!-- 登录
-->
<el
-form
:model
="loginUser"
:rules
="rules"
ref
="loginForm"
label
-width
="100px"
class="login-form sign-in-form"
>
<el
-form
-item label
="邮箱" prop
="email">
<el
-input v
-model
="loginUser.email" placeholder
="Enter Email..." />
</el
-form
-item
>
<el
-form
-item label
="密码" prop
="password">
<el
-input
v
-model
="loginUser.password"
type
="password"
placeholder
="Enter Password..."
/>
</el
-form
-item
>
<el
-form
-item
>
<el
-button
@click
="handleLogin('loginForm')"
type
="primary"
class="submit-btn"
>提交
</el
-button
>
</el
-form
-item
>
<!-- 找回密码
-->
<el
-form
-item
>
<p
class="tiparea">忘记密码
<a
>立即找回
</a
></p
>
</el
-form
-item
>
</el
-form
>
<!-- 注册
-->
<!-- <h1
>注册
</h1
> -->
</div
>
</div
>
<!-- 左右切换动画
-->
<div
class="panels-container">
<div
class="panel left-panel">
<div
class="content">
<h3
>Row
,row
,row your boat
</h3
>
<p
>Gentlely down the stream
</p
>
<button @click
="signUpMode = !signUpMode" class="btn transparent">
注册
</button
>
</div
>
<!-- <img src
="@/assets" alt
=""> -->
</div
>
<div
class="panel right-panel">
<div
class="content">
<h3
>Merrily
,merrily
,merrily
,merrily
,</h3
>
<p
>Life is but a dream
</p
>
<button @click
="signUpMode = !signUpMode" class="btn transparent">
登录
</button
>
</div
>
<!-- <img src
="@/assets" alt
=""> -->
</div
>
</div
>
</div
>
</template
>
<script
>
import { ref
, reactive
, getCurrentInstance
} from 'vue'
export default {
name: 'LoginRegister',
components: {},
// Vue3语法糖
// Vue2是通过data和methods传递数据和方法
// Vue3将data和methods直接耦合在了一起
setup() {
// 通过解构getCurrentInstance,获取this,这里的this就是ctx
const { ctx
} = getCurrentInstance()
// 登录/注册模式
const signUpMode
= ref(false)
// 登录表单
const loginUser
= reactive({
email: '',
password: ''
})
// 校验规则
const rules
= reactive({
email: [
{
required: true,
type: 'email',
message: 'email格式错误',
trigger: 'blur'
}
],
password: [
{ required: true, message: '密码不得为空', trigger: 'blur' },
{ min: 6, max: 30, message: '密码长度必须在6到30之间', trigger: 'blur' }
]
})
// 触发登录方法
const handleLogin = (formName) => {
console
.log(ctx
)
ctx
.$refs
[formName
].validate((valid) => {
if (valid
) {
console
.log('submit!')
} else {
console
.log('error submit!')
return false
}
})
}
return { signUpMode
, loginUser
, rules
, handleLogin
}
}
}
</script
>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
点击提交,完成验证:
4.类型匹配和代码抽离
4.1 代码抽离
创建utils文件夹和loginValidators.ts文件,将LoginRegister.vue中的loginUser和rules剪切抽离到该文件中,LoginRegister.vue再通过import导入。测试正常运行。
loginValidators.ts:
import { ref
, reactive
} from 'vue'
// 登录表单
export const loginUser
= reactive({
email: '',
password: ''
})
// 校验规则
export const rules
= reactive({
email: [
{
required: true,
type: 'email',
message: 'email格式错误',
trigger: 'blur'
}
],
password: [
{ required: true, message: '密码不得为空', trigger: 'blur' },
{ min: 6, max: 30, message: '密码长度必须在6到30之间', trigger: 'blur' }
]
})
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
4.2 类型匹配
4.2.1 ts文件类型匹配
将鼠标悬浮在 loginUser 的 reactive 上,可以看到对应的类型提示,写入interface User 并复制提示。rules重复操作。
import { ref
, reactive
} from 'vue'
interface User{
email: string
;
password: string
;
}
// 登录表单
export const loginUser
= reactive
<User
>({
email: '',
password: ''
})
interface Rules{
email: {
required: boolean
;
type: string
;
message: string
;
trigger: string
;
}[];
password: ({
required: boolean
;
message: string
;
trigger: string
;
min
?: undefined;
max
?: undefined;
} | {
min: number
;
max: number
;
message: string
;
trigger: string
;
required
?: undefined;
})[];
}
// 校验规则
export const rules
= reactive
<Rules
>({
email: [
{
required: true,
type: 'email',
message: 'email格式错误',
trigger: 'blur'
}
],
password: [
{ required: true, message: '密码不得为空', trigger: 'blur' },
{ min: 6, max: 30, message: '密码长度必须在6到30之间', trigger: 'blur' }
]
})
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
此时如果将字段修改为不符合规范的类型,则会有报错提示
这对于初次使用ts的同学可能不太适应,认为完全没有必要。但是这其实对于大型项目的维护来说,相对比js友好许多。
4.2.2 vue文件中的ts类型匹配
(1)在script标签中加入lang="ts"标识,发现参数都没有类型匹配。
(2)类型匹配
1、对于any类型的变量——ctx,使用// @ts-ignore进行类型忽略
2、对于其他类型的变量,在变量后加入:类型即可,比如formName:string和valid:boolean
5.抽离登录组件
(1)创建组件LoginForm.vue,将LoginRegister.vue中的表单内容(包括组件、数据、方法和样式,顺便对样式做了点优化)复制到该文件中。
LoginForm:
<template
>
<!-- 登录
-->
<el
-form
:model
="loginUser"
:rules
="rules"
ref
="loginForm"
label
-width
="100px"
class="login-form sign-in-form"
>
<el
-form
-item label
="邮箱" prop
="email">
<el
-input v
-model
="loginUser.email" placeholder
="Enter Email..." />
</el
-form
-item
>
<el
-form
-item label
="密码" prop
="password">
<el
-input
v
-model
="loginUser.password"
type
="password"
placeholder
="Enter Password..."
/>
</el
-form
-item
>
<el
-form
-item
>
<el
-button
@click
="handleLogin('loginForm')"
type
="primary"
class="submit-btn"
>提交
</el
-button
>
</el
-form
-item
>
<!-- 找回密码
-->
<el
-form
-item
>
<p
class="tiparea">忘记密码
<a
>立即找回
</a
></p
>
</el
-form
-item
>
</el
-form
>
</template
>
<script lang
="ts">
import { getCurrentInstance
} from 'vue'
export default {
name: 'LoginForm',
props: {
loginUser: {
type: Object
,
required: true
},
rules: {
type: Object
,
required: true
}
},
setup() {
// 通过解构getCurrentInstance,获取this,这里的this就是ctx
// @ts-ignore
const { ctx
} = getCurrentInstance()
// 触发登录方法
const handleLogin = (formName: string) => {
console
.log(ctx
)
ctx
.$refs
[formName
].validate((valid: boolean) => {
if (valid
) {
console
.log('submit!')
} else {
console
.log('error submit!')
return false
}
})
}
return { handleLogin
}
}
}
</script
>
<style scoped
>
/* register */
.login
-form
,
.register
-form
{
background
-color
: #fff
;
padding: 50px 80px 20px 20px
;
border
-radius
: 5px
;
box
-shadow
: 0px 5px 10px #cccc
;
}
.submit
-btn
{
width: 100%;
}
.tiparea
{
text
-align
: right
;
font
-size
: 12px
;
color: #
333;
width: 100%;
}
.tiparea a
{
color: #409eff
;
}
</style
>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
6. 实现注册表单
其实完全可以仿照登录组件的写法,先在LoginRegister.vue中写出form组件,填充form数据,实现表单验证,最后再抽离出来。但是如果已经熟练的话,建议可以直接分为3个部分写完(ts——对应的数据和验证规则,component——组件,vue——引入到父组件中)
6.1 创建注册表单ts——存放注册表单及其验证规则
创建registerValidator.ts文件,用于存放注册表单及其验证规则。
可以先复制之前的loginValidator.ts文件的内容,然后进行修改(注意确认密码password2的验证规则写法)。
registerValidator.ts:
import { reactive
} from 'vue'
interface RegisterUser{
name:string
;
email: string
;
password: string
;
password2: string
;
role:string
}
// 登录表单
export const registerUser
= reactive
<RegisterUser
>({
name:'',
email: '',
password: '',
password2: '',
role:''
})
interface RegisterRules{
name: {
required: boolean
;
message: string
;
trigger: string
;
}[];
email: {
required: boolean
;
type: string
;
message: string
;
trigger: string
;
}[];
password: ({
required: boolean
;
message: string
;
trigger: string
;
} | {
min: number
;
max: number
;
message: string
;
trigger: string
;
})[];
password2: ({
required: boolean
;
message: string
;
trigger: string
;
} | {
min: number
;
max: number
;
message: string
;
trigger: string
;
} | {
validator:(rule: RegisterRules, value: string, callback: any)=>any
;
trigger:string
})[];
role: {
required: boolean
;
message: string
;
trigger: string
;
}[];
}
const validatePass2 = (rule: RegisterRules, value: string, callback: any) => {
if (value
=== '') {
callback(new Error('请再次输入密码'))
} else if (value
!== registerUser
.password
) {
callback(new Error("两次输入的密码不一致!"))
} else {
callback()
}
}
// 校验规则
export const registerRules
= reactive
<RegisterRules
>({
name: [
{
required: true,
message: '用户名不得为空',
trigger: 'blur'
}
],
email: [
{
required: true,
type: 'email',
message: 'email格式错误',
trigger: 'blur'
}
],
password: [
{ required: true, message: '密码不得为空', trigger: 'blur' },
{ min: 6, max: 30, message: '密码长度必须在6到30之间', trigger: 'blur' }
],
password2: [
{ required: true, message: '确认密码不得为空', trigger: 'blur' },
{ min: 6, max: 30, message: '密码长度必须在6到30之间', trigger: 'blur' },
{ validator: validatePass2
, trigger: 'blur' }
],
role: [
{
required: true,
message: '角色不得为空',
trigger: 'blur'
}
],
})
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
完成后将 registerUser 和 registerRules 引入到LoginRegister.vue中备用。
6.2 创建注册表单组件
创建注册表单组件RegisterForm.vue,模仿或者直接复制LoginForm.vue组件,稍作修改(包括样式、数据和方法)
<template
>
<!-- 登录
-->
<el
-form
:model
="registerUser"
:rules
="registerRules"
ref
="registerForm"
label
-width
="100px"
class="register-form sign-up-form"
>
<el
-form
-item label
="用户名" prop
="name">
<el
-input v
-model
="registerUser.name" placeholder
="Enter Name..." />
</el
-form
-item
>
<el
-form
-item label
="邮箱" prop
="email">
<el
-input v
-model
="registerUser.email" placeholder
="Enter Email..." />
</el
-form
-item
>
<el
-form
-item label
="密码" prop
="password">
<el
-input
v
-model
="registerUser.password"
type
="password"
placeholder
="Enter Password..."
/>
</el
-form
-item
>
<el
-form
-item label
="确认密码" prop
="password2">
<el
-input
v
-model
="registerUser.password2"
type
="password"
placeholder
="Enter Password again..."
/>
</el
-form
-item
>
<el
-form
-item label
="角色" prop
="role">
<el
-select v
-model
="registerUser.role">
<el
-option label
="管理员" value
="admin"></el
-option
>
<el
-option label
="用户" value
="user"></el
-option
>
<el
-option label
="游客" value
="visitor"></el
-option
>
</el
-select
>
</el
-form
-item
>
<el
-form
-item
>
<el
-button
@click
="handleRegister('registerForm')"
type
="primary"
class="submit-btn"
>提交
</el
-button
>
</el
-form
-item
>
</el
-form
>
</template
>
<script lang
="ts">
import { getCurrentInstance
} from 'vue'
export default {
name: 'registerForm',
props: {
registerUser: {
type: Object
,
required: true
},
registerRules: {
type: Object
,
required: true
}
},
setup() {
// 通过解构getCurrentInstance,获取this,这里的this就是ctx
// @ts-ignore
const { ctx
} = getCurrentInstance()
// 触发登录方法
const handleRegister = (formName: string) => {
console
.log(ctx
)
ctx
.$refs
[formName
].validate((valid: boolean) => {
if (valid
) {
console
.log('submit!')
} else {
console
.log('error submit!')
return false
}
})
}
return { handleRegister
}
}
}
</script
>
<style scoped
>
/* register */
.login
-form
,
.register
-form
{
background
-color
: #fff
;
padding: 50px 80px 20px 20px
;
border
-radius
: 5px
;
box
-shadow
: 0px 5px 10px #cccc
;
}
.submit
-btn
{
width: 100%;
}
.tiparea
{
text
-align
: right
;
font
-size
: 12px
;
color: #
333;
width: 100%;
}
.tiparea a
{
color: #409eff
;
}
</style
>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
6.3 在LoginRegister.vue中引入使用
最后在LoginRegister.vue中引入使用即可
7. 封装axios
7.1 下载axios
(1)使用命令npm i axios下载axios
7.2 封装axios
创建utils/http.ts文件,用于封装axios请求(为了避免混乱,所以取名http.ts,不过叫做axios也无不可)。
http.ts:
import axios
,{AxiosRequestConfig
,AxiosResponse
} from 'axios'
import { ElLoading
} from 'element-plus'
import { ElMessage
} from 'element-plus'
let loading:any
;
const startLoading = () =>{
interface Options{
lock: boolean
;
text: string
;
background: string
;
}
const options:Options
= {
lock: true,
text: 'Loading',
background: 'rgba(0, 0, 0, 0.7)'
}
loading
= ElLoading
.service(options
)
}
const endLoading = ()=>{
loading
.close()
}
// 请求拦截
axios
.interceptors
.request
.use((config:AxiosRequestConfig<any>)=>{
// 开始Loading
startLoading()
return config
})
// 响应拦截
axios
.interceptors
.response
.use((res:AxiosResponse<any, any>)=>{
// 结束Loading
endLoading()
// console.log('成功响应拦截',res)
// 如果请求成功直接返回响应数据
if(res
.status
=== 200){
return res
.data
}
},error=>{
// 结束Loading
endLoading()
// console.log('失败响应拦截',error)
const { response: res
} = error
const msg
= typeof res
.data
=== 'string' ? res
.data
: res
.data
.error
|| '请求失败,请稍后重试'
ElMessage
.error(msg
)
// 错误提醒
return Promise
.reject(error
)
})
export default axios
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
7.3 解决跨域问题(配置vue.config.js,设置代理)
创建vue.config.js文件,配置如下:
module
.exports
= {
devServer: {
open: true,
host: 'localhost',
port: 8080,
https: false,
hotOnly: false,
// 设置跨域
proxy: {
'/api': {
target: 'http://imissu.herokuapp.com',
ws: true,
changeOrigin: true,
pathRewrite: {
'^api': ''
}
}
},
before: (app) => {}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
7.4 使用axios发起请求
API地址:http://imissu.herokuapp.com/
7.4.1 创建api文件夹,规范使用api(推荐)
(1)创建api/loginRegister.ts,引入axios,规范export注册接口
import axios
from '@/utils/http'
// 注册接口
export function register(params: any) {
return axios({
url: '/api/v1/auth/register',
method: 'post',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
data: params
})
}
(2)在注册组件中使用
<template
>
<!-- 登录
-->
<el
-form
:model
="registerUser"
:rules
="registerRules"
ref
="registerForm"
label
-width
="100px"
class="register-form sign-up-form"
>
<el
-form
-item label
="用户名" prop
="name">
<el
-input v
-model
="registerUser.name" placeholder
="Enter Name..." />
</el
-form
-item
>
<el
-form
-item label
="邮箱" prop
="email">
<el
-input v
-model
="registerUser.email" placeholder
="Enter Email..." />
</el
-form
-item
>
<el
-form
-item label
="密码" prop
="password">
<el
-input
v
-model
="registerUser.password"
type
="password"
placeholder
="Enter Password..."
/>
</el
-form
-item
>
<el
-form
-item label
="确认密码" prop
="password2">
<el
-input
v
-model
="registerUser.password2"
type
="password"
placeholder
="Enter Password again..."
/>
</el
-form
-item
>
<el
-form
-item label
="角色" prop
="role">
<el
-select v
-model
="registerUser.role">
<el
-option label
="管理员" value
="admin"></el
-option
>
<el
-option label
="用户" value
="user"></el
-option
>
<el
-option label
="游客" value
="visitor"></el
-option
>
</el
-select
>
</el
-form
-item
>
<el
-form
-item
>
<el
-button
@click
="handleRegister('registerForm')"
type
="primary"
class="submit-btn"
>提交
</el
-button
>
</el
-form
-item
>
</el
-form
>
</template
>
<script lang
="ts">
import { getCurrentInstance
} from 'vue'
import { useRouter
} from 'vue-router'
import { register
} from '@/api/loginRegister'
// import { ElMessage } from 'element-plus'
export default {
name: 'registerForm',
props: {
registerUser: {
type: Object
,
required: true
},
registerRules: {
type: Object
,
required: true
}
},
setup(props: any) {
// 通过解构getCurrentInstance,获取this,这里的this就是ctx
// @ts-ignore
const { ctx
, proxy
} = getCurrentInstance()
const router
= useRouter()
// 触发登录方法
const handleRegister = (formName: string) => {
console
.log(ctx
)
ctx
.$refs
[formName
].validate(async (valid: boolean) => {
if (valid
) {
// const res = await proxy.$http({
// url: '/api/v1/auth/register',
// method: 'post',
// headers: {
// 'Content-Type': 'application/json;charset=UTF-8'
// },
// data: props.registerUser
// })
const res
= await register(props
.registerUser
)
proxy
.$message
.success(res
.data
)
router
.push('/')
} else {
return false
}
})
}
return { handleRegister
}
}
}
</script
>
<style scoped
>
/* register */
.login
-form
,
.register
-form
{
background
-color
: #fff
;
padding: 50px 80px 20px 20px
;
border
-radius
: 5px
;
box
-shadow
: 0px 5px 10px #cccc
;
}
.submit
-btn
{
width: 100%;
}
.tiparea
{
text
-align
: right
;
font
-size
: 12px
;
color: #
333;
width: 100%;
}
.tiparea a
{
color: #409eff
;
}
</style
>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
登录功能模仿注册功能即可。
7.4.2 全局注册axios(不推荐,也没必要)
(1)在main.ts中全局挂载axios
import axios
from '@/utils/http'
app
.config
.globalProperties
.$http
= axios
(2)在注册组件中使用,关键代码:
// @ts-ignore
const { ctx
, proxy
} = getCurrentInstance()
const res
= await proxy
.$http({
url: '/api/v1/auth/register',
method: 'post',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
data: props
.registerUser
})
(3)不推荐的原因是,随着版本的更替,貌似axios全局挂载的位置也发生了变化,之前是在ctx,之后的版本又换成了proxy;另外一个原因是,这种方式不便于一个接口多处使用,复用性较差。
8.总结
Vue3 和 Vue2 的几个明显的区别:
(1)Vue2使用的选项式API,Vue3使用的是组合式API。前者随着项目页面体积的增大,对于代码的管理会给使用者带来更大的心智负担;后者组合式的写法,将data和methods等组合在一起,更容易理解和使用。不过对于初学者而言,可能会有些不太适应。
(2)Vue2使用的js构建的源码和使用方式,Vue3使用ts构建的源码,使用方式也支持ts,对于大型项目而言,更加友好,不过对于小型项目而言,往往使用者无法一下子看出ts对于强类型支持带来的好处,相反会觉得麻烦和没有必要。
(3)由于该项目是为了简要说明Vue3和Vue2在页面中的区别,方便急于使用Vue3的同学构建项目和页面,所以没有将Vue3更多的特性展示出来。在下一篇文章中,将会通过一个更加完整的项目,对Vue3的更多其他特性以及和Vue2的区别进行深入的解析和说明,敬请期待。