完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)

目录

前言

 一、本地存储

1.1 cookie

1.1.3 新建 cookie.ts

1.1.5 源代码

1.1.6 提交代码

1.2 localStorage

1.2.1 新建 storage.ts

1.2.2 实现存取函数

1.2.3 使用一下

1.2.4 提交代码

二、日期相关

2.1 格式化

2.1.1 新建 date.ts

2.1.2 完成格式化函数

2.1.3 测试一下

2.1.4 提交代码

三、设备区分

3.1 使用 userAgent

3.1.1 新建 device.ts

3.1.2 源代码

3.1.3 提交代码

3.2 h5 唤起 App

3.2.1 安装 callapp-lib

3.2.2 实现唤起函数

3.2.3 源代码

3.2.4 提交代码

四、判断 js 类型

4.1 实现各种 is 函数

4.1.1 新建 is.ts

4.1.2 源代码

4.1.3 提交代码

4.2 应用 is 方法

4.2.1 修改 env.ts

4.2.2 修改 storage.ts

4.2.3 提交代码

五、上传文件

5.1 自定义上传单个方法

5.1.1 新建 file.ts

5.1.2 实现选择文件函数

5.1.3 应用

5.1.4 提交代码

5.2 自定义上传多个文件

5.2.1 增加 webMulChooseFile 方法

5.2.2 提交代码

5.3 使用组件库上传

六、下载文件

6.1 浏览器能预览的文件

6.1.1 通过链接下载

6.2 浏览器不能预览的文件

6.2.1 下载txt

6.2.2 下载 exe、zip

6.2.3 提交代码

七、节流和防抖

7.1 安装 lodash-es

7.2 安装 @types/lodash-es

7.3 应用

7.4 提交代码

八、部署

8.1 本地打包

8.1.1 运行 npm run build

8.1.2 解决问题

8.1.3 重新打包

8.1.4 预览

8.1.5 提交代码

8.2 使用vercel 

8.2.1 创建 github 仓库

8.2.2 vercel 导入 github 仓库

8.2.3 预览

小结

总结


前言

在看这篇文章之前,请先看之前两章的内容,分别是项目搭建和请求封装,本篇文章是在前两篇文章基础上进行的,这篇文章是整个 vite + ts + vue3 项目的完结篇。

在第二篇文章中我们提到还剩两部分的内容没有写,一个是公共工具方法,一个是项目部署,这两部分也是这篇文章的主要内容。

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第1张图片

在开始之前,请去仓库克隆代码,本篇文章是在这个提交的基础上进行的,建议在这个提交记录新建新分支然后开始一步一步的学习。

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第2张图片

本篇文章的全部代码相关的流程图如下:

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第3张图片

 一、本地存储

1.1 cookie

对于 cookie 建议是用 js-cookie 模块,方便我们设置过期时间。

 pnpm i js-cookie
pnpm i @types/js-cookie -D

1.1.3 新建 cookie.ts

在 src/global 下新建 cookie.ts

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第4张图片

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第5张图片

1.1.5 源代码

import Cookies from 'js-cookie'

export const setCookie = Cookies.set.bind(Cookies)
export const removeCookie = Cookies.remove.bind(Cookies)

export const getCookie = Cookies.get.bind(Cookies)

1.1.6 提交代码

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第6张图片

1.2 localStorage

1.2.1 新建 storage.ts

在 src/global 下新建文件 storage.ts

1.2.2 实现存取函数

// 所有 key 用常量存储起来
export enum StorageKeys {
	TOKEN = 'TOKEN',
	NAME_LIST = 'NAME_LIST',
}

export function setStorage(key: string, val: string): void {
	localStorage.setItem(key, val)
}

export function getStorage(key: string): string | null {
	return localStorage.getItem(key) || ''
}

export function removeStorage(key: string): void {
	localStorage.removeItem(key)
}

// 判断是否存在
export function hasStorage(key: string): boolean {
	return getStorage(key) !== null
}
// 取数组类型的,直接返回解析后的数组
export function getStorageArray(key: string): Array | null {
	const data = localStorage.getItem(key)
	if (data === null) {
		return data
	}
	try {
		const arr = JSON.parse(data)
		if (Array.isArray(arr)) {
			return arr
		}
		localStorage.removeItem(key)
	} catch (err) {
		console.log('json parse error getStorageArray', err)
	}
	return null
}
// 取对象类型的,直接返回解析后的对象
export function getStorageObject(key: string): Object | null {
	const data = localStorage.getItem(key)
	if (data === null) {
		return data
	}
	try {
		const obj = JSON.parse(data)
		if (Object.prototype.toString.call(obj) === '[object Object]') {
			return obj
		}
		localStorage.removeItem(key)
	} catch (err) {
		console.log('json parse error getStorageObject', err)
	}
	return null
}

1.2.3 使用一下

在 login.vue 中使用一下

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第7张图片完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第8张图片

1.2.4 提交代码

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第9张图片

二、日期相关

2.1 格式化

格式化日期比较简单,如果仅仅是这个功能就没必要引入 moment 包,自己写就行。

2.1.1 新建 date.ts

在 src/global 下面新建 date.ts

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第10张图片

2.1.2 完成格式化函数

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第11张图片

2.1.3 测试一下

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第12张图片

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第13张图片

2.1.4 提交代码

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第14张图片

三、设备区分

3.1 使用 userAgent

3.1.1 新建 device.ts

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第15张图片

3.1.2 源代码

// ie 基本上已经不用了
export function isIE(UA: string): number {
	const isIE = UA.indexOf('compatible') > -1 && UA.indexOf('MSIE') > -1 //判断是否IE<11浏览器
	const isIE11 = UA.indexOf('Trident') > -1 && UA.indexOf('rv:11.0') > -1
	if (isIE) {
		const reIE = new RegExp('MSIE (\\d+\\.\\d+);')
		reIE.test(UA)
		const fIEVersion = parseFloat(RegExp['$1'])
		if (fIEVersion == 7) {
			return 7
		} else if (fIEVersion == 8) {
			return 8
		} else if (fIEVersion == 9) {
			return 9
		} else if (fIEVersion == 10) {
			return 10
		} else {
			return 6 //IE版本<=7
		}
	} else if (isIE11) {
		return 11
	} else {
		return -1 //不是ie浏览器
	}
}

function isMac(UA: string): boolean {
	return /macintosh|mac os x/i.test(UA) ? true : false
}

function isWin32(UA: string): boolean {
	return /win32|wow32/i.test(UA) ? true : false
}

function isWechat(UA: string): boolean {
	return /MicroMessenger/i.test(UA) ? true : false
}

function isQQ(UA: string): boolean {
	return /QQ/i.test(UA) ? true : false
}

function isMoible(UA: string): boolean {
	return /(Android|webOS|iPhone|iPod|BlackBerry|Mobile)/i.test(UA) ? true : false
}

export function isIOS(UA: string): boolean {
	return /iPhone|iPad|iPod/i.test(UA) ? true : false
}

function isAndroid(UA: string): boolean {
	return /Android/i.test(UA) ? true : false
}
// 返回类型按需设置
export function deviceType(UA: string): { type: string; env?: string } {
	if (isMoible(UA)) {
		if (isIOS(UA)) {
			if (isWechat(UA)) {
				return {
					type: 'ios',
					env: 'wechat',
				}
			}
			if (isQQ(UA)) {
				return {
					type: 'ios',
					env: 'qq',
				}
			}
			return {
				type: 'ios',
			}
		}
		if (isAndroid(UA)) {
			if (isWechat(UA)) {
				return {
					type: 'android',
					env: 'wechat',
				}
			}
			if (isQQ(UA)) {
				return {
					type: 'android',
					env: 'qq',
				}
			}
			return {
				type: 'android',
			}
		}

		return {
			type: 'mobile',
		}
	} else {
		if (isMac(UA)) {
			return {
				type: 'mac',
			}
		}
		let env = ''
		if (isIE(UA) > 0) {
			env = 'ie'
		}
		// 注意区分 window 的 32位/64位
		if (isWin32(UA)) {
			return {
				type: 'win32',
				env: env,
			}
		}
		return {
			type: 'win64',
			env: env,
		}
	}
}

export function isPC(UA = window.navigator?.userAgent) {
	const agent = deviceType(UA)
	return ['pc', 'mac', 'win32', 'win64'].includes(agent.type)
}

3.1.3 提交代码

3.2 h5 唤起 App

3.2.1 安装 callapp-lib

pnpm i callapp-lib

3.2.2 实现唤起函数

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第16张图片

3.2.3 源代码

import CallApp from 'callapp-lib'
// 移动端唤醒应用
export function callApp(isIOS: boolean) {
	let packageName = ''
	// 一般来说 ios 和 android 的包名不一样
	if (isIOS) {
		packageName = 'com.mobile.android.vite.name' // ios 移动端提供
	} else {
		packageName = 'com.mobile.ios.vite.name' // android 移动端提供
	}
	const appStoreUrl = 'https://itunes.apple.com/cn/app/xxxx' // 填写appstore的下载地址
	const androidUrl = 'https://yingyongbao' // 软件应用宝地址

	const options = {
		scheme: {
			protocol: 'vite', // 移动端设置的
		},
		intent: {
			package: packageName,
			scheme: 'vite', // 移动端设置的
		},
		timeout: 2000,
		appstore: appStoreUrl,
		yingyongbao: androidUrl,
		fallback: 'https://www.xxx.com/',
	}
	const callLib = new CallApp(options)
	callLib.open({
		path: 'xxx.app/openwith', // 移动端提供
		callback: () => {
			if (isIOS) {
				window.location.href = appStoreUrl // ios 直接跳转到appStore 地址即可
			} else {
				// android 跳转
				const link = document.createElement('a')
				link.target = '_blank'
				link.href = androidUrl
				link.click()
			}
		},
	})
}

3.2.4 提交代码

四、判断 js 类型

4.1 实现各种 is 函数

4.1.1 新建 is.ts

在 src/global 下新建 is.ts,可以用 is 这个第三方模块,但是没必要,因为逻辑很简单

4.1.2 源代码

const { isInteger } = Number
const { toString } = Object.prototype

export function isNumber(v: unknown): v is number {
	return typeof v === 'number' && !Number.isNaN(v) && Number.isFinite(v)
}

export function isInt(v: unknown): boolean {
	return isNumber(v) && isInteger(v)
}

export function isFloat(v: unknown): boolean {
	return isNumber(v) && !isInteger(v)
}

export function isString(v: unknown): v is string {
	return typeof v === 'string'
}

export function isBoolean(v: unknown): v is boolean {
	return v === true || v === false
}

export function isFunction(v: unknown): v is (...args: unknown[]) => unknown {
	return typeof v === 'function'
}

export const { isArray } = Array

export function isPlainObject(v: unknown): v is Record {
	return toString.call(v) === '[object Object]'
}

export function isRegExp(v: unknown): v is RegExp {
	return v instanceof RegExp
}

export function isDate(v: unknown): v is Date {
	return v instanceof Date
}

export function isNull(v: unknown): v is null {
	return v === null
}

export function isDef(v: unknown): v is Exclude {
	return v !== undefined && v !== null
}

export function isUndef(v: unknown): v is undefined {
	return v === undefined
}

export function isUndefOrNull(v: unknown): v is null | undefined {
	return v === undefined || v === null
}

4.1.3 提交代码

4.2 应用 is 方法

4.2.1 修改 env.ts

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第17张图片

4.2.2 修改 storage.ts

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第18张图片

4.2.3 提交代码

五、上传文件

5.1 自定义上传单个方法

5.1.1 新建 file.ts

在 src/global 下新建文件 file.ts

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第19张图片

5.1.2 实现选择文件函数

import { isNull } from '@/global/is'

export function webChooseFile(cb: (file: File) => unknown, accept?: string): void {
	const id = 'file-selector-99999999'
	let input = document.getElementById(id) as HTMLInputElement
	if (isNull(input)) {
		input = document.createElement('input')
		input.id = id
		input.type = 'file'
		input.style.position = 'fixed'
		input.style.left = '-10000px'
		document.body.appendChild(input)
	} else {
		input.value = ''
	}
	if (accept) {
		input.accept = accept
	} else {
		input.removeAttribute('accept')
	}
	input.onchange = (): void => {
		if (input.files?.length) {
			cb(input.files[0])
		}
	}
	input.classList.add('selectFile')
	const e = document.createEvent('MouseEvent') as unknown as Event
	e.initEvent('click', false, true)
	input.dispatchEvent(e)
}

5.1.3 应用

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第20张图片

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第21张图片

5.1.4 提交代码

5.2 自定义上传多个文件

5.2.1 增加 webMulChooseFile 方法

和 5.1 中的单个文件差不多,只是多了个参数

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第22张图片

5.2.2 提交代码

5.3 使用组件库上传

可以使用组件库自带的上传组件

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第23张图片

六、下载文件

6.1 浏览器能预览的文件

6.1.1 通过链接下载

如下载 pdf 

export function webDownloadFileByUrl(url: string, name: string): void {
	const xhr = new XMLHttpRequest()
	xhr.open('GET', url, true)
	xhr.responseType = 'blob'
	xhr.onload = (): void => {
		if (xhr.status === 200) {
			const a = document.createElement('a')
			a.download = name
			a.href = URL.createObjectURL(xhr.response)
			a.click()
		}
	}
	xhr.send()
}

6.2 浏览器不能预览的文件

6.2.1 下载txt

export function downloadToTxt(text: string, filename: string) {
	const element = document.createElement('a')
	element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text))
	element.setAttribute('download', filename)
	element.style.display = 'none'
	document.body.appendChild(element)
	element.click()
}

6.2.2 下载 exe、zip

直接使用 location.href 跳转即可

window.location.href = 'https://xxx.exe'

6.2.3 提交代码

 更多下载场景,可以参考这篇文章、这篇文章

七、节流和防抖

7.1 安装 lodash-es

pnpm i lodash-es

lodash 是一个强大的工具库,lodash-es 是lodash库按照 es 模块导出的,所以我们的项目中需要安装 loadsh-ts 更加方便。

lodash 的功能模块也可以单独安装,比如  lodash.throttle (节流)和 lodash.debounce ( 防抖)都可以单独安装,可以根据需要。

7.2 安装 @types/lodash-es

pnpm i @types/lodash-es -D

7.3 应用

Lodash Documentation lodash 库的应用不做详细解释,可以参考官方文档

7.4 提交代码

八、部署

在部署之前我们要保证自己的代码能够在本地打包,运行 npm run build

8.1 本地打包

8.1.1 运行 npm run build

发现报了一个错误

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第24张图片

8.1.2 解决问题

在 tsconfig.json 中加入  allowJs: true即可

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第25张图片

8.1.3 重新打包

发现可以正常打包了

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第26张图片

8.1.4 预览

运行 npm run preview,可以运行成功

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第27张图片

8.1.5 提交代码

8.2 使用vercel 

每个公司部署代码的方式不尽相同,有的公司是用gitlab 的 ci/cd 流程 + docker + k8s 等一套流程,但是这些工作很多都是架构组的流程实现的,我们前端的小白就学会怎么用就行,后续当然还是要学会更好。

作为一个学习的项目,弄一套流程还是挺麻烦的,但是我们可以使用 vercel 这个工具,简单易学。

8.2.1 创建 github 仓库

不幸的是,vercel 暂时不支持 gitee 仓库,所以我要先把仓库弄到 github 上面。在github 中 导入仓库即可,我的github仓库地址是这个

8.2.2 vercel 导入 github 仓库

跟着步骤一步一步来就行

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第28张图片

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第29张图片

导入之后他会自动打包,而且如果你github 仓库有内容更新,vercel 这边也会重新打包,很厉害吧!

8.2.3 预览

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第30张图片

他会自动给你分配一个域名

完整的 vite + ts + vue3 项目,所有常用的方法一览,全部流程已完结(第三篇)_第31张图片

好了,就是这么简单,你可以开始画你的页面了。

小结

部署这一块有一个问题,就是我整个教程用的都是 gitee 仓库,开始是因为有些时候没有工具不能访问 github。但是如果要使用 vercel 部署就不克避免的要把仓库迁移到 github 了。所以如果你有科学上网的工具,也完全可以最开始就新建一个github 仓库,只是一个管理工具罢了,不必纠结。怎么方便怎么来。

总结

至此,完整的vite + ts + vue3 项目的教程已经全部完成,现在可以说是克隆就能用了。

第一篇教程

第二篇教程

gitee 仓库地址

github 仓库地址

之后可能会有优化的内容会在后续更新。

内容很多,难免疏漏,有不对的地方,欢迎评论区指正。


好了,现在你领导来了,说:“小王啊,我们有个新项目,你先把项目搭建起来吧。”

这个时候你要首先判断是不是官网?需不需要服务端渲染?服务端渲染的项目需要用nuxt 等框架。我之后会出一个类似的 nuxt3 + vue +ts 教程,欢迎大家持续关注。

如果是普通的管理系统的项目,那就没问题了,你自信的说,好嘞,然后顺手把这个教程中的仓库克隆下来,改改名字(一定要改名字啊),摸会鱼,就可以交差了~~

你可能感兴趣的:(前端工程化系统教程,vue.js,前端,javascript)