vue3进阶学习
作者:互联网
vue3进阶学习
目的:
- 加强对vue3的学习
- 了解vue3在生产环境下需要安装什么插件。
1、Vue3安装
上节我们采用NPM 的方法来学习vue。
这次使用构建工具来构建Vue项目。
现在官方推荐使用 create-vue 来创建基于 Vite 的新项目
1.1、Vite简单了解
官方中文文档:https://cn.vitejs.dev/
官方推荐使用Vite来构建vue项目,这里简单了解一下。
Vite主要功能是用于打包场景的增强功能。
Vite作为一个基于浏览器原生ESM的构建工具,它省略了开发环境的打包过程,利用浏览器去解析imports,在服务端按需编译返回。同时,在开发环境拥有速度快到惊人的模块热更新,且热更新的速度不会随着模块增多而变慢。因此,使用Vite进行开发,至少会比Webpack快10倍左右。
1.2、项目构建
前提条件
- 已安装 15.0 或更高版本的 Node.js
- 用Visual Studio Code + Volar 扩展。
1、通过命令来初始化 vue3 项目。
npm init vue@latest
创建项目时,可以根据自己需求去添加组件。
2、启动项目
# 进入刚刚创建项目的目录
cd vue3-demo
# 更新依赖
npm install
# 启动项目
npm run dev
1.3、项目结构说明
1、新建目录如下:
打开APP.vue
,你会发现Vue 的单文件组件是网页开发中 HTML、CSS 和 JavaScript 三种语言经典组合的自然延伸。<template>
、<script>
和 <style>
三个块在同一个文件中封装、组合了组件的视图、逻辑和样式。完整的语法定义可以查阅 SFC 语法说明。
1.4、添加登录页面
1、把对应没有用的页面先删除。
2、编写登录页
App.vue
<script setup>
import Login from './views/Login.vue'
</script>
<template>
<main>
<Login />
</main>
</template>
<style scoped>
</style>
创建views
文件夹,我们一般会将页面放在views
里。
Login.vue
<script setup>
</script>
<template>
<div class="container">
<div class="login-wrapper">
<div class="header">登录</div>
<div class="form-wrapper">
<input type="text" name="username" placeholder="账号" class="input-item">
<input type="password" name="password" placeholder="密码" class="input-item">
<div class="btn">登录</div>
</div>
</div>
</div>
</template>
<style scoped>
.container {
height: 100%;
}
.login-wrapper {
background-image: linear-gradient(to right, #fbc2eb, #a6c1ee);
width: 358px;
height: 588px;
border-radius: 15px;
padding: 0 50px;
margin: 0 auto;
}
.header {
font-size: 38px;
font-weight: bold;
text-align: center;
line-height: 200px;
}
.input-item {
display: block;
width: 100%;
margin-bottom: 20px;
border: 0;
padding: 10px;
border-bottom: 1px solid rgb(128, 125, 125);
font-size: 15px;
outline: none;
}
.input-item:placeholder {
text-transform: uppercase;
}
.btn {
text-align: center;
padding: 10px;
width: 100%;
margin-top: 40px;
background-image: linear-gradient(to right, #a6c1ee, #fbc2eb);
color: #fff;
}
</style>
效果如果下:
1.5、模拟登录成功跳转页面
Vue Router官方文档:https://router.vuejs.org/zh/
1、添加Vue Router依赖
由于页面跳转需要路由(相当于控制你要去哪个页面的控制器)。
# 在项目的根目录下
npm install vue-router@4
2、添加router文件
可以新增
routers
文件夹,存放router
文件,看个人习惯。
添加router文件
import { createRouter, createWebHistory } from 'vue-router'
// 导入路由组件.
import Login from './views/Login.vue'
import UserList from './views/UserList.vue'
// 创建路由实例
export const router = createRouter({
history: createWebHistory(),
// 定义路由
routes: [
{ path: '/', component: Login },
{ path: '/userList', component: UserList }
]
})
UserList
是用来登录成功后跳转的页面。
<script>
export default {
}
</script>
<template>
<div>
<h1>用户管理</h1>
</div>
</template>
<style scoped>
</style>
3、修改main.js
import { createApp } from 'vue'
import App from './App.vue'
import { router } from './router'
// import './assets/main.css'
// createApp(App).mount('#app')
const app = createApp(App)
// 注册路由
app.use(router)
app.mount('#app')
4、修改Login.vue
主要是添加点击事件和路由跳转
export default {
data() {
return {
login: {
username: '',
password: ''
}
}
},
methods: {
toLogin() {
// 这里可以判断账号和密码是否为空。
this.$router.push('/userList')
}
}
}
5、修改App.vue
router-view
显示与路由的页面。按创建顺序来,默认显示第一个。
类似html的iframe
标签。
6、验证路由是否生效
点击登录,发现url产生变化,也发现页面跳转了,证明路由生效了。
1.6、指令复习
演示一个用户管理功能,用于快速学习vue为目的。
UserList.vue
<script>
export default {
data(){
return {
userForm:{
name: '',
age: ''
},
userList: [{ name: '小明', age:22 },
{ name: '大白', age:23 },
{ name: '张三', age:24 }],
delIds:[]
}
},
methods:{
addUser(){
this.userList.push(this.userForm)
this.userForm = {
name: '',
age: ''
}
},
delUser(){
let i = 0;
for (const del of this.delIds.sort()) {
this.userList.splice(del-i,1);
i++;
}
this.delIds=[]
}
}
}
</script>
<template>
<div>
<h1>用户管理</h1>
<form action="">
<input type="text" placeholder="用户名" v-model="userForm.name" >
<input type="text" placeholder="年龄" v-model.number="userForm.age" @keyup.enter="addUser">
<input type="button" value="添加" @click="addUser">
<input type="button" value="删除" @click="delUser">
</form>
<ul>
<li v-for="(user,index) in userList">
<input type="checkbox" v-model="delIds" :value="index" />
姓名:{{user.name}},
年龄:{{user.age}}
</li>
</ul>
</div>
</template>
<style scoped>
</style>
发现页面并不美观,下面我们引用UI组件库。
2、安装 UI 组件库
目前常用于VUE3的几款UI组件库:
- Element-Plus
- Ant Design
- Naive UI
- .....
2.1、安装Element Plus
# 在项目的根目录下
npm install element-plus --save
2.2、项目使用
main.js
import { createApp } from 'vue'
import App from './App.vue'
import { router } from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// import './assets/main.css'
// createApp(App).mount('#app')
const app = createApp(App)
// 注册路由
app.use(router)
app.use(ElementPlus)
app.mount('#app')
改造UserList.vue
<script>
export default {
data(){
return {
userForm:{
name: '',
age: ''
},
userList: [{ name: '小明', age:22 },
{ name: '大白', age:23 },
{ name: '张三', age:24 }],
delIds:[]
}
},
methods:{
addUser(){
this.userList.push(this.userForm)
this.userForm = {
name: '',
age: ''
}
},
delUser(){
let i = 0;
for (const del of this.delIds.sort()) {
this.userList.splice(del-i,1);
i++;
}
this.delIds=[]
}
}
}
</script>
<template>
<div>
<h1>用户管理</h1>
<form action="">
<input type="text" placeholder="用户名" v-model="userForm.name" >
<input type="text" placeholder="年龄" v-model.number="userForm.age" @keyup.enter="addUser">
<input type="button" value="添加" @click="addUser">
<input type="button" value="删除" @click="delUser">
</form>
<ul>
<li v-for="(user,index) in userList">
<input type="checkbox" v-model="delIds" :value="index" />
姓名:{{user.name}},
年龄:{{user.age}}
</li>
</ul>
</div>
</template>
<style scoped>
</style>
发现比之前好看多了。
3、axios
3.1、axios是什么?
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
功能与Ajax是一样的。都是请求后端接口获取数据。
3.2、安装axios
# 在项目的根目录下
npm install --save axios vue-axios
请求方法的别名:
为方便使用,官方为所有支持的请求方法提供了别名,可以直接使用别名来发起请求:
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
注意:在使用别名方法时, url、method、data 这些属性都不必在配置中指定。
3.3、项目使用
main.js
import { createApp } from 'vue'
import App from './App.vue'
import { router } from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import axios from 'axios'
import VueAxios from 'vue-axios'
// import './assets/main.css'
// createApp(App).mount('#app')
const app = createApp(App)
// 注册路由
app.use(router)
app.use(ElementPlus)
app.use(VueAxios, axios)
app.mount('#app')
在public
添加测试数据userList.json
[
{ "name": "小明", "age": 22 },
{ "name": "大白", "age": 23 },
{ "name": "张三", "age": 24 }
]
改造UserList.vue
<script>
export default {
created(){
this.getUserList()
},
data(){
return {
userForm:{
name: '',
age: ''
},
userList: [],
delIds:[]
}
},
methods:{
getUserList(){
// 获取public下的test.json文件数据
this.axios.get('/userList.json')
.then(res => (
//console.log(res)
this.userList = res.data
))
.catch(error => ( // 请求失败处理
console.log(error)
))
},
addUser(){
this.userList.push(this.userForm)
this.userForm = {
name: '',
age: ''
}
},
delUser(val){
let i = 0;
for (const del of this.delIds.sort()) {
this.userList.splice(del-i,1);
i++;
}
this.delIds=[]
},
selectObjs(val){
this.delIds = [];
for (const it of val) {
this.delIds.push(this.userList.indexOf(it));
}
}
}
}
</script>
<template>
<div>
<h1>用户管理</h1>
<el-form :model="userForm" :inline="true">
<el-form-item>
<el-input placeholder="用户名" v-model="userForm.name" />
</el-form-item>
<el-form-item>
<el-input placeholder="年龄" v-model.number="userForm.age" @keyup.enter="addUser" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="addUser">添加</el-button>
<el-button type="danger" @click="delUser">删除</el-button>
</el-form-item>
</el-form>
<el-table :data="userList" stripe @selection-change="selectObjs">
<el-table-column type="selection" width="55" />
<el-table-column prop="name" label="名称" width="180" />
<el-table-column prop="age" label="年龄" width="180" />
</el-table>
</div>
</template>
<style scoped>
</style>
4、组合式函数
为什么要使用setup组合?
- 在 Vue 应用的概念中,“组合式函数”(Composables) 是一个利用 Vue 的组合式 API 来封装和复用有状态逻辑的函数。
- 有点像把功能封装好之后,其它地方调用即可
鼠标跟踪器示例
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const x = ref(0)
const y = ref(0)
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
</script>
<template>Mouse position is at: {{ x }}, {{ y }}</template>
但是,如果我们想在多个组件中复用这个相同的逻辑呢?我们可以把这个逻辑以一个组合式函数的形式提取到外部文件中
// mouse.js
import { ref, onMounted, onUnmounted } from 'vue'
// 按照惯例,组合式函数名以“use”开头
export function useMouse() {
// 被组合式函数封装和管理的状态
const x = ref(0)
const y = ref(0)
// 组合式函数可以随时更改其状态。
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
// 一个组合式函数也可以挂靠在所属组件的生命周期上
// 来启动和卸载副作用
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
// 通过返回值暴露所管理的状态
return { x, y }
}
下面是它在组件中使用的方式:
<script setup>
import { useMouse } from './mouse.js'
const { x, y } = useMouse()
</script>
<template>Mouse position is at: {{ x }}, {{ y }}</template>
组合式与普通的写法在于:
-
组合式有
setup
。 -
组合式不能直接使用生命周期钩子,需要通过
import { onMounted } from 'vue'
才可以。
5、自定义指令
除了 Vue 内置的一系列指令 (比如 v-model
或 v-show
) 之外。Vue 还允许你注册自定义的指令。
下面是一个自定义指令的例子,当一个 input 元素被 Vue 插入到 DOM 中后,它会被自动聚焦:
const focus = {
mounted: (el) => el.focus()
}
export default {
directives: {
// 在模板中启用 v-focus
focus
}
}
<input v-focus />
上面是局部使用,如果我们想全局使用怎么做?
const app = createApp({})
// 使 v-focus 在所有组件中都可用
app.directive('focus', {
/* ... */
})
6、Router进阶
在上面我们只是简单使用Router来进行跳转。
实际上Router的功能很强大。
因为它是控制页面的跳转的,你完全可以在跳转前判断要不要跳转当前页面。
6.1、路由带参数
const routes = [
// 动态字段以冒号开始
{ path: '/users/:id', component: User },
]
//接收参数
this.$route.params
6.2、嵌套路由
跟iframe
标签里套iframe
标签是一样的。
const routes = [
{
path: '/user/:id',
component: User,
// 请注意,只有子路由具有名称
children: [{ path: '', name: 'user', component: UserHome }],
},
]
6.3、导航守卫
主要用来通过跳转前来处理请求。
使用 router.beforeEach
注册一个全局前置守卫:
const router = createRouter({ ... })
router.beforeEach((to, from) => {
// to: 即将要进入的目标,
// from: 当前导航正要离开的路由
// ...
// 返回 false 取消跳转,这里也可以重定向到别的页面。
return false
// 将用户重定向到登录页面
// return { name: 'Login' }
})
6.4、路由元信息
可以自定义一定属性在路由上,例如,某一个路由需要登录后才能访问。
const routes = [
{
path: '/posts',
component: PostsLayout,
children: [
{
path: 'new',
component: PostsNew,
// 只有经过身份验证的用户才能创建帖子
meta: { requiresAuth: true }
},
{
path: ':id',
component: PostsDetail
// 任何人都可以阅读文章
meta: { requiresAuth: false }
}
]
}
]
例子:判断页面是否要登录才能访问
router.beforeEach((to, from) => {
if (to.meta.requiresAuth && !auth.isLoggedIn()) {
// 此路由需要授权,请检查是否已登录
// 如果没有,则重定向到登录页面
return {
path: '/login',
// 保存我们所在的位置,以便以后再来
query: { redirect: to.fullPath },
}
}
})
7、axios进阶
1、主要对axios
进行封装成工具来使用。
import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
// create an axios instance
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // api 的 base_url
withCredentials: true, // 跨域请求时发送 cookies
timeout: 5000 // request timeout
})
// request interceptor
service.interceptors.request.use(
config => {
// Do something before request is sent
if (store.getters.token) {
// 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
config.headers['X-Token'] = getToken()
}
return config
},
error => {
// Do something with request error
console.log(error) // for debug
Promise.reject(error)
}
)
// response interceptor
service.interceptors.response.use(
/**
* If you want to get information such as headers or status
* Please return response => response
*/
/**
* 下面的注释为通过在response里,自定义code来标示请求状态
* 当code返回如下情况则说明权限有问题,登出并返回到登录页
* 如想通过 XMLHttpRequest 来状态码标识 逻辑可写在下面error中
* 以下代码均为样例,请结合自生需求加以修改,若不需要,则可删除
*/
response => {
const res = response.data
if (res.code !== 20000) {
Message({
message: res.message,
type: 'error',
duration: 5 * 1000
})
// 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// 请自行在引入 MessageBox
// import { Message, MessageBox } from 'element-ui'
MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
store.dispatch('user/resetToken').then(() => {
location.reload() // 为了重新实例化vue-router对象 避免bug
})
})
}
return Promise.reject('error')
} else {
return res
}
},
error => {
console.log('err' + error) // for debug
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
export default service
配置来源:https://github.com/PanJiaChen/vue-element-admin/blob/v4.0.0/src/utils/request.js
使用:
import request from '@/utils/request'
export function getList(query) {
return request({
url: '/demo/list',
method: 'get',
params: query
})
}
8、项目发布
# 在项目的根目录下
npm run build
执行完成后,会在 Vue 项目下会生成一个 dist 目录
9、后话
写到这里,日常开发也差不多满足了
如果想更快理解,可以参照一些优秀项目来进行学习。
多练即可。
文章参考:
https://cn.vuejs.org/guide/introduction.html
https://zhuanlan.zhihu.com/p/482851017
https://www.runoob.com/vue3/vue3-tutorial.html
推荐后台管理模板:
http://blog.lgf196.top/ant-simple-pro-document/
https://gitee.com/codeZyZ_admin/vue3-composition-admin
https://gitee.com/panjiachen/vue-element-admin/tree/master/
标签:axios,const,进阶,app,router,学习,vue,vue3,import 来源: https://www.cnblogs.com/galenblog/p/16644181.html