Skip to content

背景

背景

最近在对公司node+jquery捞系统基层进行版本升级,使用最新技术栈vue + ts + vite + pinia,对于捞系统原有页面将会进行iframe不会再其基础上进行修改,大大减少了维护成本,但是由于其页面较多,且页面之间存在关联,所以需要对页面进行缓存,避免重复加载,提升用户体验,其中也遇到了一系列兼容问题,总结如下:

对于系统升级,当然要使用最新技术栈了,这样公司使用的技术栈就会统一,也不会因为技术栈不统一导致个人成长缓慢;对于相对系列问题也可以进行小组探讨;

从计划开始部署到真正上手改造花费将近一周时间,底层框架结构采用vue,里层内容采用iframe链接老项目页面;

Start

开始进行对系统技术的升级,大致升级的范围:

  • 登录,重置密码重构,摒弃原来jquery页面
  • 路由,权限的重置,需要后端开发人员配合,现在市面上的中后台系统的路由和权限基本都是后端来管理,很少使用前端路由
  • 基础库,方法的编写,对于常用的方法,hooks需要统一封装管理
  • 常用枚举的封装,接口定义,类型定义
  • 请求拦截,相应的封装;

环境的配置

当然对于企业项目,多环境已经是常见的,开发环境,测试环境,预发布环境,线上环境等等;对于这些环境一些请求的域名,配置参数当然也是不一样的,这时候就可以在.env文件中配置,大概配置项如下:

sh
VITE_APP_API_URL='http://www.wangxiaoze.wang'
VITE_APP_API_KEY='abc'
VITE_APP_APP_ID='123456'

# 当然对于iframe页面需要相对环境的域名配置
VITE_APP_IFRAME_HOST='http://www.wangxiaoze.wang'

utils, hooks 等基础配置的封装

  1. utils基础的方法,正则的封装等等;
  2. hooks的封装,对于一些常用的方法,比如loadingmessagedialogconfirmloading等方法,需要统一封装管理;
  3. config对一些系统级的配置项,如:七牛的配置,标题,logo 的配置等等
  4. store-pinia的配置
  5. axios的封装,对于请求的拦截,响应的封装,请求的封装等等
  6. api的封装,对于一些接口的封装,如:七牛的图片上传,七牛的图片删除,七牛的图片列表等等

axios, api 的封装

对于axios的使用,代码如下:

typescript
const instance: AxiosInstance = axios.create({
	baseURL: `${import.meta.env.VITE_APP_BASE_URL}`,
	timeout: 60000,
});

// 请求拦截器
instance.interceptors.request.use(
	(config: InternalAxiosRequestConfig) => {
		// 根据自己的需要进行修改
		return config;
	},
	error => error
);

// 响应拦截器
instance.interceptors.response.use(
	(response: AxiosResponse) => {
		// 根据自己的需要进行修改
		return response.data;
	},
	error => {
		return Promise.reject(error.response);
	}
);

interface IHttpResult<T> {
	code: number;
	message: string;
	data: T;
	success: boolean;
}

// 泛型T: 返回接口字段类型 泛型U: 是参数的数据类型
const httpServer = {
	get<T = any, U = any>(url: string, params: U): Promise<IHttpResult<T>> {
		return instance.request(getParamsConfig(url, "get", params));
	},
	post<T = any, U = any>(url: string, params: U): Promise<IHttpResult<T>> {
		return instance.request(getParamsConfig(url, "post", params));
	},
	put<T = any, U = any>(url: string, params: U): Promise<IHttpResult<T>> {
		return instance.request(getParamsConfig(url, "put", params));
	},
	delete<T = any, U = any>(url: string, params: U): Promise<IHttpResult<T>> {
		return instance.request(getParamsConfig(url, "delete", params));
	},
	postForQuery<T = any, U = any>(
		url: string,
		params: U
	): Promise<IHttpResult<T>> {
		return instance.request(
			getParamsConfig(
				url,
				"post",
				qs.stringify(params, {
					arrayFormat: "repeat",
				})
			)
		);
	},
};

export { instance as axios, httpServer };

系统采用的是ts,那么对于api的管理使用枚举整理,相关api的配置如下:

typescript
enum UsetApi {
	// 七牛图片上传
	UploadImage = "/api/upload/image",
	// 七牛图片删除
	DeleteImage = "/api/upload/delete",
	// 七牛图片列表
	ImageList = "/api/upload/list",
}

import { httpServer } from "@/http";

export function getList<T, U>(data: U) {
	return httpServer.get<T>(UsetApi.ImageList, data);
}

iframe 内嵌页面缓存

刚开始使用iframe会发现一个问题,就是iframe内嵌页面刷新后,iframe会重新加载,导致页面会重新刷新,iframe 资源也会重新加载,会造成性能影响 那么如何解决呢?

  • 使用v-show这样就可以避免刷新资源的问题
  • 定位将 iframe 页面定位可视区域之外;
vue
<iframe
	v-for="item in routes"
	:key="item.path"
	v-show="item.path === route.path"
/>

虽然发现不会再次请求资源,刷新页面,但是会发现一个细节问题,那就是滚动条不会定位到上次的位置,这样用户频繁跳转页面,滚动条不会定位,会造成一定的使用不便;

另外的一中方案可以解决此类问题;

老系统的预览图片,打开标签页兼容

捞系统的预览图片会打开新的标签页,但是新系统要使用element-plus的预览图片的样式,当然打开标签页也是同样问题;

想要同时解决新老系统的兼容问题,那么可以参考一下方案:

js
// 老系统
window.parent.postMessage(
	{
		command: "open",
		data: {
			url: url,
		},
	},
	"*"
);

// 新系统
window.addEventListener("message", function (e) {
	if (e.data.command === "open") {
		// 根据自己的情况操作逻辑
		// 判断是否是当前页面打开
	}
});

// 移除,避免叠加
window.removeEventListener("message", function (e) {
	if (e.data.command === "open") {
		// 根据自己的情况操作逻辑
		// 判断是否是当前页面打开
	}
});

当然图片或者其他也是类似操作;

wangxiaoze | MIT License.