前端学习第九站——Vue3基础篇

目录

一、环境搭建

创建项目

 编码 IDE

修改端口

配置代理

项目架构 

二、Vue组件 

main.ts

属性绑定

事件绑定

表单绑定

计算属性

 xhr

axios

环境变量

baseURL

 拦截器

条件和列表 

监听器

 vueuse

 useRequest

usePagination(分页)

子组件


一、环境搭建

创建项目

采用 vite 作为前端项目的打包,构建工具

npm init vite@latest

 按照提示操作

前端学习第九站——Vue3基础篇_第1张图片

cd 项目目录
npm install
npm run dev 

 编码 IDE

推荐采用微软的 VSCode 作为开发工具,到它的官网 Visual Studio Code - Code Editing. Redefined 下载安装即可。

前端学习第九站——Vue3基础篇_第2张图片

要对 *.vue 做语法支持,还要安装一个 Volar 插件  

前端学习第九站——Vue3基础篇_第3张图片

修改端口

 打开项目根目录下 vite.config.ts

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  server: {
    port: 7070
  }
})
  • 文档地址:配置 Vite {#configuring-vite} | Vite中文网 (vitejs.cn)

配置代理

为了避免前后端服务器联调时, fetch、xhr 请求产生跨域问题,需要配置代理,同样是修改项目根目录下 vite.config.ts

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  server: {
    port: 7070,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true
      }
    }
  }
})

项目架构 

前端学习第九站——Vue3基础篇_第4张图片

  • index.html 为主页面

  • package.json npm 配置文件

  • tsconfig.json typescript 配置文件

  • vite.config.ts vite 配置文件

  • public 静态资源

  • src/components 可重用组件

  • src/model 模型定义

  • src/router 路由

  • src/store 共享存储

  • src/views 视图组件

二、Vue组件 

ue 的组件文件以 .vue 结尾,每个组件由三部分组成  





  • script 代码部分,控制模板的数据来源和行为

  • template 模板部分,由它生成 html 代码

  • style 样式部分

根组件是 src/App.vue,先来个 Hello,world 例子


  • {{msg}} 用来把一个变量绑定到页面上某个位置

  • 绑定的变量必须用 ref 函数来封装

    • ref 返回的是【响应式】数据,即数据一旦变化,页面展示也跟着变化

main.ts

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'

createApp(App)
  .mount('#app')
  • createApp 是创建一个 Vue 应用程序,它接收的参数 App 即之前我们看到的根组件

  • mount 就是把根组件生成的 html 代码片段【挂载】到 index.html 中 id 为 app 的 html 元素上

可以修改自己的组件文件,挂载到主页面。

新建 src/views/E0.vue,内容如下


修改 main.ts 将自己的组件文件挂载  

import { createApp } from 'vue'
import './style.css'
// import App from './App.vue'
import E0 from './views/E0.vue'

createApp(E0).mount('#app')

打开浏览器控制台,进入 Vue 的开发工具,尝试做如下修改

前端学习第九站——Vue3基础篇_第5张图片

当把 msg 的值由 "Hello, World" 改为 "你好" 时,会发现页面展示同步发生了变化 ,这个就是响应式。

属性绑定

  • 【:属性名】用来将标签属性与【响应式】变量绑定 v-bind



事件绑定

  • 【@事件名】用来将标签属性与函数绑定,事件发生后执行函数内代码



表单绑定

  • 用 v-model 实现双向绑定,即

    • javascript 数据可以同步到表单标签

    • 反过来用户在表单标签输入的新值也会同步到 javascript 这边

  • 双向绑定只适用于表单这种带【输入】功能的标签,其它标签的数据绑定,单向就足够了

  • 复选框这种标签,双向绑定的 javascript 数据类型一般用数组





计算属性

 有时在数据展示时要做简单的计算



看起来较为繁琐,可以用计算属性改进



  • fullName 即为计算属性,它具备缓存功能,即 firstName 和 lastName 的值发生了变化,才会重新计算

  • 如果用函数实现相同功能,则没有缓存功能。


  

 xhr

浏览器中有两套 API 可以和后端交互,发送请求、接收响应,fetch api 前面我们已经介绍过了,另一套 api 是 xhr,基本用法如下。

const xhr = new XMLHttpRequest()
xhr.onload = function() {
    console.log(xhr.response)
}
xhr.open('GET', 'http://localhost:8080/api/students')
xhr.responseType = "json"
xhr.send()

xhr.onload函数会在xhr接收到响应后才执行方法。 

但这套 api 虽然功能强大,但比较老,不直接支持 Promise,因此有必要对其进行改造。

function get(url: string) {
  return new Promise((resolve, reject)=>{
    const xhr = new XMLHttpRequest()
    xhr.onload = function() {
      if(xhr.status === 200){
        resolve(xhr.response)
      } else if(xhr.status === 404) {
        reject(xhr.response)
      } // 其它情况也需考虑,这里简化处理
    }
    xhr.open('GET', url)
    xhr.responseType = 'json'
    xhr.send()
  })
}
  • Promise 对象适合用来封装异步操作,并可以配合 await 一齐使用

  • Promise 在构造时,需要一个箭头函数,箭头函数有两个参数 resolve 和 reject

    • resolve 是异步操作成功时被调用,把成功的结果传递给它,最后会作为 await 的结果返回

    • reject 在异步操作失败时被调用,把失败的结果传递给它,最后在 catch 块被捉住

  • await 会一直等到 Promise 内调用了 resolve 或 reject 才会继续向下运行

 走代理和不走代理速度比较

调用示例1:同步接收结果,不走代理  

try {
  const resp = await get("http://localhost:8080/api/students")
  console.log(resp)
} catch (e) {
  console.error(e)
}

调用示例2:走代理

try {
  const resp = await get('/api/students')
  console.log(resp)  
} catch(e) {
  console.log(e)
}

 会发现,走代理明显速度慢不少。

axios

 axios 就是对 xhr api 的封装,手法与前面例子类似。

安装

npm install axios

一个简单的例子



  • onMounted 指 vue 组件生成的 html 代码片段,挂载完毕后被执行

再来看一个 post 例子  




环境变量

  • 开发环境下,联调的后端服务器地址是 http://localhost:8080

  • 上线改为生产环境后,后端服务器地址为 http://itheima.com

这就要求我们区分开发环境和生产环境,这件事交给构建工具 vite 来做

默认情况下,vite 支持上面两种环境,需要我们分别在对应根目录下创建两个配置文件

  • .env.development - 开发环境

  • .env.production - 生产环境

针对以上需求,分别在两个文件中加入

VITE_BACKEND_API_BASE_URL = 'http://localhost:8080'

VITE_BACKEND_API_BASE_URL = 'http://itheima.com'

 然后在代码中使用 vite 给我们提供的特殊对象 import.meta.env,就可以获取到 VITE_BACKEND_API_BASE_URL 在不同环境下的值

import.meta.env.VITE_BACKEND_API_BASE_URL

默认情况下,不能智能提示自定义的环境变量,做如下配置:新增文件 src/env.d.ts 并添加如下内容

/// 

interface ImportMetaEnv {
  readonly VITE_BACKEND_API_BASE_URL: string
  // 更多环境变量...
}

interface ImportMeta {
  readonly env: ImportMetaEnv
}
  • 参考文档地址 环境变量和模式 | Vite 官方中文文档 (vitejs.dev)

前端学习第九站——Vue3基础篇_第6张图片

baseURL

 可以自己创建一个 axios 对象,方便添加默认设置,新建文件 /src/api/request.ts

// 创建新的 axios 对象
import axios from 'axios'
const _axios = axios.create({
  baseURL: import.meta.env.VITE_BACKEND_API_BASE_URL
})

export default _axios

然后在其它组件中引用这个 ts 文件,例如 /src/views/E8.vue,就不用自己拼接路径前缀了 

 拦截器

// 创建新的 axios 对象
import axios from 'axios'
const _axios = axios.create({
  baseURL: import.meta.env.VITE_BACKEND_API_BASE_URL
})

// 请求拦截器
_axios.interceptors.request.use(
  (config)=>{ // 统一添加请求头
    config.headers = {
      Authorization: 'aaa.bbb.ccc'
    }
    return config
  },
  (error)=>{ // 请求出错时的处理
    return Promise.reject(error)
  }
)

// 响应拦截器
_axios.interceptors.response.use(
  (response)=>{ // 状态码  2xx
    // 这里的code是自定义的错误码
    if(response.data.code === 200) {
      return response
    }     
    else if(response.data.code === 401) {       
      // 情况1
      return Promise.resolve({})
    }
    // ... 
  },
  (error)=>{ // 状态码 > 2xx, 400,401,403,404,500
    console.error(error) // 处理了异常
    if(error.response.status === 400) {
      // 情况1
    } else if(error.response.status === 401) {
      // 情况2
    } 
    // ...
    return Promise.resolve({})
  }
)

export default _axios

处理响应时,又分成两种情况

  1. 后端返回的是标准响应状态码,这时会走响应拦截器第二个箭头函数,用 error.response.status 做分支判断

  2. 后端返回的响应状态码总是200,用自定义错误码表示出错,这时会走响应拦截器第一个箭头函数,用 response.data.code 做分支判断

另外

  • Promise.reject(error) 类似于将异常继续向上抛出,异常由调用者(Vue组件)来配合 try ... catch 来处理

  • Promise.resolve({}) 表示错误已解决,返回一个空对象,调用者中接到这个空对象时,需要配合 ?. 来避免访问不存在的属性。

条件和列表 

首先,新增模型数据 src/model/Model8080.ts

export interface Student {
  id: number;
  name: string;
  sex: string;
  age: number;
}

// 如果 spring 错误,返回的对象格式
export interface SpringError {
  timestamp: string,
  status: number,
  error: string,
  message: string,
  path: string
}

// 如果 spring 成功,返回 list 情况
export interface SpringList {
  data: T[],
  message?: string,
  code: number
}

// 如果 spring 成功,返回 page 情况
export interface SpringPage {
  data: { list: T[], total: number },
  message?: string,
  code: number
}

// 如果 spring 成功,返回 string 情况
export interface SpringString {
  data: string,
  message?: string,
  code: number
}

import { AxiosResponse } from 'axios'
export interface AxiosRespError extends AxiosResponse { }
export interface AxiosRespList extends AxiosResponse> { }
export interface AxiosRespPage extends AxiosResponse> { }
export interface AxiosRespString extends AxiosResponse { }

其中

  • AxiosRespPage 代表分页时的响应类型

  • AxiosRespList 代表返回集合时的响应类型

  • AxiosRespString 代表返回字符串时的响应类型

  • AxiosRespError 代表 Spring 出错时时的响应类



  • 加入泛型是为了更好的提示

  • v-if 与 v-else 不能和 v-for 处于同一标签

  • template 标签还有一个用途,就是用它少生成一层真正 html 代码

  • 可以看到将结果封装为响应式数据还是比较繁琐的,后面会使用 useRequest 改进

监听器

利用监听器,可以在【响应式】的基础上添加一些副作用,把更多的东西变成【响应式的】

  • 原本只是数据变化 => 页面更新

  • watch 可以在数据变化时 => 其它更新

下述代码就可以通过watch监听事件和sessionStorage 来实现响应式数据。

watch监听当数据发生变化是,存入sessionStorage,然后在通过sessionStorage获取新值



  • 名称为 useXXXX 的函数,作用是返回带扩展功能的【响应式】数据

  • localStorage 即使浏览器关闭,数据还在

  • sessionStorage 数据工作在浏览器活动期间

 vueuse

 安装

npm install @vueuse/core

一些函数的用法

useMouse:鼠标移动、useCount:数字运算、useStorage: 存取数据


 useRequest

响应式的 axios 封装,官网地址 一个 Vue 请求库 | VueRequest (attojs.org)  

首先安装 vue-request  

npm install vue-request@next

 组件



  • data.value 的取值一开始是 undefined,随着响应返回变成 axios 的响应对象

  • 用 computed 进行适配

usePagination(分页)

 在 src/model/Model8080.ts 中补充类型说明

export interface StudentQueryDto {
  name?: string,
  sex?: string,
  age?: string, // 18,20
  page: number,
  size: number
}
  • js 中类似于 18,20 这样以逗号分隔字符串,会在 get 传参时转换为 java 中的整数数组

编写组件



usePagination 只需要定义一次,后续还想用它内部的 axios 发请求,只需调用 run 函数

子组件

 例1

定义子组件 Child1



 父组件引用


例2

首先添加类型说明 model/ModelRandomUser.ts  

import { AxiosResponse } from "axios";
export interface AxiosRespResults extends AxiosResponse{}

export interface Results {
  info: {
    page: number,
    results: number
  },
  results: Result[]
}

export interface Result {
  gender: 'male' | 'female',
  name: {
    first: string,
    last: string
  },
  location: {
    country: string
  },
  picture: {
    medium: string
  },
  login: {
    username: string
  }
}

 子组件不变,父组件使用子组件



 如果觉得 Result 数据结构嵌套太复杂,还可以做一个类型映射  



  • resultToUser 将 Result 类型映射为 User 类型

你可能感兴趣的:(前端,前端,学习,vue.js)