实现 this 指向
This commit is contained in:
@@ -2,16 +2,32 @@
|
|||||||
* Copyright (c) 2020. bmy
|
* Copyright (c) 2020. bmy
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { VueCustomize } from "@logic/base.type";
|
import VueRouter, { Route } from 'vue-router'
|
||||||
|
|
||||||
|
export interface Methods {
|
||||||
|
StartUp?(): void;
|
||||||
|
$route: Route;
|
||||||
|
$router: VueRouter;
|
||||||
|
// 可添加其他需要的Vue属性,如$el/$data/$refs等
|
||||||
|
$el?: HTMLElement;
|
||||||
|
$data?: Record<string, any>;
|
||||||
|
$refs?: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* logic 层的父类
|
* logic 层的父类
|
||||||
* 主要实现 页面公共参数和ajax方法的地方
|
* 主要实现 页面公共参数和ajax方法的地方
|
||||||
*/
|
*/
|
||||||
export class BaseLogic {
|
export class BaseLogic<T> implements Methods {
|
||||||
|
// 泛型参数T表示Vue实例的类型
|
||||||
|
protected _?: T; // 保留this._以便向后兼容
|
||||||
|
|
||||||
|
$route!: Route;
|
||||||
|
$router!: VueRouter;
|
||||||
|
$el?: HTMLElement | undefined;
|
||||||
|
$data?: Record<string, any> | undefined;
|
||||||
|
|
||||||
|
|
||||||
// 保存Vue对象
|
|
||||||
public _!: any;
|
|
||||||
|
|
||||||
public page: number = 1;
|
public page: number = 1;
|
||||||
public total_page: number = 1;
|
public total_page: number = 1;
|
||||||
@@ -26,14 +42,19 @@ export class BaseLogic {
|
|||||||
|
|
||||||
// 请求参数
|
// 请求参数
|
||||||
public PageParams: { limit: number, page: number } = {
|
public PageParams: { limit: number, page: number } = {
|
||||||
limit : 10, page : 1
|
limit: 10, page: 1
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
constructor() {
|
||||||
* 【页面中公共的多次被用到的接口】可以在这个父类中定义,
|
|
||||||
* 子类logic中直接使用,避免方法的冗余
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
public async DepartmentListRequest(): Promise<void> {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 组件初始化完成后调用
|
||||||
|
StartUp?(): void;
|
||||||
|
|
||||||
|
// 合并Vue实例到Logic实例
|
||||||
|
mergeVueInstance(vueInstance: T) {
|
||||||
|
// 保存Vue实例的引用,以便在Logic实例中可以访问到Vue实例
|
||||||
|
this._ = vueInstance;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ import { Autowired } from "@ann/ioc.annotation";
|
|||||||
import { BaseLogic } from "@logic/base.logic";
|
import { BaseLogic } from "@logic/base.logic";
|
||||||
import { Methods, VueCustomize } from "@logic/base.type";
|
import { Methods, VueCustomize } from "@logic/base.type";
|
||||||
|
|
||||||
export class AboutLogic <T extends VueCustomize> extends BaseLogic implements Methods {
|
export class AboutLogic<T extends VueCustomize> extends BaseLogic<T> implements Methods {
|
||||||
|
|
||||||
constructor(_: T) {
|
constructor(_: T) {
|
||||||
super();
|
super();
|
||||||
this._ = _
|
(this as any)._ = _; // 使用类型断言来解决TypeScript的类型检查问题
|
||||||
}
|
}
|
||||||
|
|
||||||
public async StartUp (): Promise<void> {
|
public async StartUp(): Promise<void> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,39 +8,40 @@ import { UserService, ResponseType } from "@service/user.service";
|
|||||||
import { BaseLogic } from "@logic/base.logic";
|
import { BaseLogic } from "@logic/base.logic";
|
||||||
import { Methods, VueCustomize } from "@logic/base.type";
|
import { Methods, VueCustomize } from "@logic/base.type";
|
||||||
|
|
||||||
export class HomeLogic<T extends VueCustomize> extends BaseLogic implements Methods {
|
export class HomeLogic<T extends VueCustomize> extends BaseLogic<T> implements Methods {
|
||||||
|
|
||||||
@Autowired()
|
@Autowired()
|
||||||
public readonly UserService!: UserService;
|
public readonly UserService!: UserService;
|
||||||
|
|
||||||
public title: string = "12222";
|
public title: string = "12222";
|
||||||
|
|
||||||
public List: ResponseType[] = [];
|
public List: ResponseType[] = [
|
||||||
|
{ user_id: 1, user_name: '测试1' },
|
||||||
|
{ user_id: 2, user_name: '测试2' },
|
||||||
|
];
|
||||||
|
|
||||||
// constructor() {
|
constructor() {
|
||||||
// super();
|
|
||||||
// }
|
|
||||||
|
|
||||||
constructor(_: T) {
|
|
||||||
super();
|
super();
|
||||||
console.log("constructor params: ", _);
|
|
||||||
this._ = _
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在这里面调用需要打开页面就执行的ajax请求
|
* 页面初始化调用的方法
|
||||||
* @constructor
|
|
||||||
*/
|
*/
|
||||||
public async StartUp (): Promise<void> {
|
public async StartUp(): Promise<void> {
|
||||||
|
// 在StartUp方法中访问$route和$router
|
||||||
|
console.log("StartUp - this: ", this);
|
||||||
|
console.log("StartUp - this.$route: ", this.$route);
|
||||||
|
console.log("StartUp - this.$router: ", this.$router);
|
||||||
|
|
||||||
await this.getData();
|
await this.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求首页数据
|
* 请求首页数据
|
||||||
*/
|
*/
|
||||||
public async getData (): Promise<void> {
|
public async getData(): Promise<void> {
|
||||||
this.List = await this.UserService.UserList({ type: 1, page: 1 });
|
// this.List = await this.UserService.UserList({ type: 1, page: 1 });
|
||||||
console.log("this.List: ", this.List);
|
// console.log("this.List: ", this.List);
|
||||||
|
|
||||||
// let res = await this.UserService.login({ type: 2, page: 2 });
|
// let res = await this.UserService.login({ type: 2, page: 2 });
|
||||||
// console.log("this.res: ", res);
|
// console.log("this.res: ", res);
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import { VueCustomize, RouterMeta } from "@logic/base.type";
|
|||||||
import { Autowired } from "@ann/ioc.annotation";
|
import { Autowired } from "@ann/ioc.annotation";
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
export default class About extends VueCustomize {
|
export default class About extends VueCustomize {
|
||||||
|
|
||||||
@Autowired(About)
|
@Autowired()
|
||||||
private logic!: AboutLogic<About>
|
private logic!: AboutLogic<About>
|
||||||
|
|
||||||
private RouterMeta: RouterMeta = {
|
private RouterMeta: RouterMeta = {
|
||||||
@@ -20,16 +20,16 @@ export default class About extends VueCustomize {
|
|||||||
isLogin: true
|
isLogin: true
|
||||||
};
|
};
|
||||||
|
|
||||||
public async created () {
|
public async created() {
|
||||||
await this.logic.StartUp();
|
await this.logic.StartUp();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 路由拦截器
|
// 路由拦截器
|
||||||
beforeRouteEnter (to: Route, from: Route, next: (to?: RawLocation | false | ((vm: Vue) => void)) => void) {
|
beforeRouteEnter(to: Route, from: Route, next: (to?: RawLocation | false | ((vm: Vue) => void)) => void) {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render () {
|
protected render() {
|
||||||
return (
|
return (
|
||||||
<div class="About">
|
<div class="About">
|
||||||
About
|
About
|
||||||
|
|||||||
@@ -18,13 +18,21 @@ import { VueCustomize, RouterMeta } from "@logic/base.type";
|
|||||||
@Component
|
@Component
|
||||||
export default class Home extends VueCustomize {
|
export default class Home extends VueCustomize {
|
||||||
|
|
||||||
|
// 可选:手动声明data(双重保障,也可仅靠装饰器自动声明)
|
||||||
|
public data() {
|
||||||
|
return {
|
||||||
|
logic: {}, // 确保Vue2初始化时劫持该属性
|
||||||
|
Utils: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public RouterMeta: RouterMeta = {
|
public RouterMeta: RouterMeta = {
|
||||||
title: '首页',
|
title: '首页',
|
||||||
showNav: true,
|
showNav: true,
|
||||||
isLogin: true
|
isLogin: true
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired(Home)
|
@Autowired()
|
||||||
private logic!: HomeLogic<Home>
|
private logic!: HomeLogic<Home>
|
||||||
|
|
||||||
@Autowired()
|
@Autowired()
|
||||||
@@ -49,6 +57,7 @@ export default class Home extends VueCustomize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public back() {
|
public back() {
|
||||||
|
this.logic.title = "44444";
|
||||||
console.log("qqqq");
|
console.log("qqqq");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,6 +70,15 @@ export default class Home extends VueCustomize {
|
|||||||
<HelloWorld msg="向HelloWorld props传参" />
|
<HelloWorld msg="向HelloWorld props传参" />
|
||||||
<input type="text" v-model={this.logic.title} />
|
<input type="text" v-model={this.logic.title} />
|
||||||
<h2>{this.logic.title}</h2>
|
<h2>{this.logic.title}</h2>
|
||||||
|
|
||||||
|
{/* 显示$route和$router信息 */}
|
||||||
|
<div class="route-info">
|
||||||
|
<h3>路由信息:</h3>
|
||||||
|
<p>路由路径: {this.$route?.path}</p>
|
||||||
|
<p>路由名称: {this.$route?.name}</p>
|
||||||
|
<p>Logic实例路由路径: {(this.logic as any).$route?.path}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
{this.ClickButton()}
|
{this.ClickButton()}
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,14 +1,184 @@
|
|||||||
/*
|
import Vue from 'vue';
|
||||||
* Copyright (c) 2020. bmy
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function Autowired(params?: any) {
|
// 1. 定义最宽松的基础类型(兼容所有场景,避开symbol索引签名限制)
|
||||||
return (target: any, propertyKey: string) => {
|
type AutowiredTarget = {
|
||||||
let typeClass = Reflect.getMetadata('design:type', target, propertyKey);
|
[key: string]: any;
|
||||||
Object.defineProperty(target, propertyKey, {
|
};
|
||||||
value: params ? new typeClass(new params) : new typeClass(),
|
|
||||||
writable: true,
|
// 2. Vue组件实例专属类型(仅声明string/number索引,运行时兼容symbol)
|
||||||
configurable: true
|
interface VueComponentInstance extends AutowiredTarget {
|
||||||
});
|
created?: (...args: any[]) => Promise<void> | void;
|
||||||
}
|
$router?: any;
|
||||||
|
$route?: any;
|
||||||
|
$el?: HTMLElement;
|
||||||
|
$data?: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Logic实例类型
|
||||||
|
interface LogicInstance extends AutowiredTarget {
|
||||||
|
mergeVueInstance?: <T extends VueComponentInstance>(vueInstance: T) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 通用构造函数类型
|
||||||
|
type Constructor<T = any> = new (...args: any[]) => T;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动注入实例装饰器
|
||||||
|
* 适配所有场景:
|
||||||
|
* - Vue组件的logic属性:自动创建Logic实例并合并Vue所有属性
|
||||||
|
* - Logic类/普通类的属性:直接创建实例并挂载
|
||||||
|
*/
|
||||||
|
export function Autowired(params?: any) {
|
||||||
|
return function (target: AutowiredTarget, propertyKey: string | symbol): void {
|
||||||
|
// 获取属性对应的类构造函数
|
||||||
|
const typeClass = Reflect.getMetadata('design:type', target, propertyKey) as Constructor;
|
||||||
|
|
||||||
|
// 仅对Vue组件的logic属性做特殊处理(运行时判断)
|
||||||
|
if (propertyKey === 'logic') {
|
||||||
|
enhanceVueLogicProperty(target as VueComponentInstance, propertyKey, typeClass);
|
||||||
|
} else {
|
||||||
|
// 所有其他场景(包括Logic类的属性):直接挂载实例
|
||||||
|
mountNormalInstance(target, propertyKey, typeClass, params);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 挂载普通实例(适配所有非Vue组件场景)
|
||||||
|
*/
|
||||||
|
function mountNormalInstance(
|
||||||
|
target: AutowiredTarget,
|
||||||
|
propertyKey: string | symbol,
|
||||||
|
typeClass: Constructor,
|
||||||
|
params?: any
|
||||||
|
): void {
|
||||||
|
if (!typeClass) {
|
||||||
|
console.warn(`类构造函数不存在,属性${String(propertyKey)}注入失败`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建实例并挂载(统一用defineProperty兼容symbol)
|
||||||
|
const instance = params ? new typeClass(params) : new typeClass();
|
||||||
|
Object.defineProperty(target, propertyKey, {
|
||||||
|
value: instance,
|
||||||
|
writable: true,
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增强Vue组件的logic属性:创建实例并合并Vue所有属性
|
||||||
|
*/
|
||||||
|
function enhanceVueLogicProperty(
|
||||||
|
target: VueComponentInstance,
|
||||||
|
propertyKey: string | symbol,
|
||||||
|
typeClass: Constructor<LogicInstance>
|
||||||
|
): void {
|
||||||
|
// 保存原始created钩子
|
||||||
|
const originalCreated: (...args: any[]) => Promise<void> | void = target.created || (() => { });
|
||||||
|
|
||||||
|
// 重写created钩子(显式指定this类型)
|
||||||
|
target.created = async function (this: VueComponentInstance): Promise<void> {
|
||||||
|
const vueInstance = this;
|
||||||
|
|
||||||
|
// 防御性判断
|
||||||
|
if (!typeClass) {
|
||||||
|
console.warn(`Logic类构造函数不存在,属性${String(propertyKey)}注入失败`);
|
||||||
|
await originalCreated.call(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建Logic实例
|
||||||
|
const logicInstance = Vue.observable(new typeClass());
|
||||||
|
|
||||||
|
// 核心修复:用Object.defineProperty兼容symbol,避开TS索引检查
|
||||||
|
Object.defineProperty(this, propertyKey, {
|
||||||
|
value: logicInstance,
|
||||||
|
writable: true,
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// 合并Vue属性(仅当存在mergeVueInstance方法时)
|
||||||
|
if (typeof logicInstance.mergeVueInstance === 'function') {
|
||||||
|
logicInstance.mergeVueInstance(vueInstance);
|
||||||
|
mergeVueProperties(logicInstance, vueInstance);
|
||||||
|
resetLogicConstructor(logicInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行原始created钩子
|
||||||
|
await originalCreated.call(this);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合并Vue实例的所有属性到Logic实例
|
||||||
|
*/
|
||||||
|
function mergeVueProperties(logicInstance: LogicInstance, vueInstance: VueComponentInstance): void {
|
||||||
|
const allProps = getAllVueProperties(vueInstance);
|
||||||
|
const excludeProps = new Set<string | symbol>(['constructor', 'prototype', '__proto__', 'mergeVueInstance']);
|
||||||
|
|
||||||
|
allProps.forEach(prop => {
|
||||||
|
if (excludeProps.has(prop)) return;
|
||||||
|
|
||||||
|
const logicPropDesc = Object.getOwnPropertyDescriptor(logicInstance, prop);
|
||||||
|
if (logicPropDesc && !logicPropDesc.configurable) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const vuePropDesc =
|
||||||
|
Object.getOwnPropertyDescriptor(Object.getPrototypeOf(vueInstance), prop) ||
|
||||||
|
Object.getOwnPropertyDescriptor(vueInstance, prop);
|
||||||
|
|
||||||
|
if (vuePropDesc) {
|
||||||
|
Object.defineProperty(logicInstance, prop, {
|
||||||
|
...vuePropDesc,
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 兜底:用defineProperty赋值,兼容symbol
|
||||||
|
Object.defineProperty(logicInstance, prop, {
|
||||||
|
value: vueInstance[prop as keyof typeof vueInstance],
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true,
|
||||||
|
writable: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (typeof prop === 'string' && !['__proto__', 'constructor'].includes(prop)) {
|
||||||
|
console.warn(`合并属性 ${String(prop)} 失败:`, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收集Vue实例的所有属性(包括原型链、Symbol)
|
||||||
|
*/
|
||||||
|
function getAllVueProperties(obj: any): Set<string | symbol> {
|
||||||
|
const props = new Set<string | symbol>();
|
||||||
|
let currentObj: any = obj;
|
||||||
|
|
||||||
|
while (currentObj && currentObj !== Object.prototype) {
|
||||||
|
Object.getOwnPropertyNames(currentObj).forEach(prop => props.add(prop));
|
||||||
|
Object.getOwnPropertySymbols(currentObj).forEach(prop => props.add(prop));
|
||||||
|
currentObj = Object.getPrototypeOf(currentObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置Logic实例的constructor指向
|
||||||
|
*/
|
||||||
|
function resetLogicConstructor(logicInstance: LogicInstance): void {
|
||||||
|
Object.defineProperty(logicInstance, 'constructor', {
|
||||||
|
value: logicInstance.constructor,
|
||||||
|
configurable: true,
|
||||||
|
enumerable: false,
|
||||||
|
writable: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
@@ -56,25 +56,25 @@ module.exports = {
|
|||||||
errors: true
|
errors: true
|
||||||
},
|
},
|
||||||
// before 这块代码都可以删除,仅仅为脚手架提供一个用于测试的接口
|
// before 这块代码都可以删除,仅仅为脚手架提供一个用于测试的接口
|
||||||
before: function (app, server) {
|
// before: function (app, server) {
|
||||||
app.all('*', function (req, res, next) {
|
// app.all('*', function (req, res, next) {
|
||||||
res.header('Access-Control-Allow-Origin', '*');
|
// res.header('Access-Control-Allow-Origin', '*');
|
||||||
res.header('Access-Control-Allow-Headers', '*');
|
// res.header('Access-Control-Allow-Headers', '*');
|
||||||
res.header('Access-Control-Allow-Methods', '*');
|
// res.header('Access-Control-Allow-Methods', '*');
|
||||||
res.header('Content-Type', 'application/json;charset=utf-8');
|
// res.header('Content-Type', 'application/json;charset=utf-8');
|
||||||
next();
|
// next();
|
||||||
});
|
// });
|
||||||
app.get('/UserList', function (req, res) {
|
// app.get('/UserList', function (req, res) {
|
||||||
res.json({
|
// res.json({
|
||||||
status: 200,
|
// status: 200,
|
||||||
message: '请求成功',
|
// message: '请求成功',
|
||||||
result: [
|
// result: [
|
||||||
{ id: 1, name: '张三' },
|
// { id: 1, name: '张三' },
|
||||||
{ id: 2, name: '李四' }
|
// { id: 2, name: '李四' }
|
||||||
]
|
// ]
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
},
|
// },
|
||||||
// proxy: {
|
// proxy: {
|
||||||
// '/api': {
|
// '/api': {
|
||||||
// target: 'http://115.159.153.142:9010/h5',
|
// target: 'http://115.159.153.142:9010/h5',
|
||||||
@@ -111,7 +111,7 @@ module.exports = {
|
|||||||
plugins: [
|
plugins: [
|
||||||
new ProgressPlugin({
|
new ProgressPlugin({
|
||||||
handler: (percentage, message, ...args) => {
|
handler: (percentage, message, ...args) => {
|
||||||
console.log(`${chalk.yellow("进度: ")}${chalk.green.bold(~~(percentage * 100) + "%")} ${args[0] ? chalk.black(args[0]) : " " } ${chalk.blue.bold(message)}`)
|
console.log(`${chalk.yellow("进度: ")}${chalk.green.bold(~~(percentage * 100) + "%")} ${args[0] ? chalk.black(args[0]) : " "} ${chalk.blue.bold(message)}`)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user