Skip to content

Commit

Permalink
实现模板数据监控及绑定
Browse files Browse the repository at this point in the history
  • Loading branch information
meepobrother committed May 4, 2019
1 parent 1cb86b1 commit 53cbdc6
Show file tree
Hide file tree
Showing 17 changed files with 196 additions and 71 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
/hooks
/platforms
/cloud
/**/package.json
Binary file added WX20190504-205634@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 22 additions & 2 deletions addon/nger-demo/template/admin/welcome/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,32 @@
import { Page } from 'nger-core';
import { Page, Input, ChangeDetectorRef } from 'nger-core';
@Page({
path: '/admin/welcome',
styleUrls: [
"./index.scss"
]
})
export class NgerDemoAdminWelcomePage {

@Input()
title: string = `小明title`;

@Input()
classStr: string = `items`

constructor(change: ChangeDetectorRef<NgerDemoAdminWelcomePage>) {
let i = 0;
setInterval(() => {
i = i + 1;
this.title += i;
this.classStr += i;
change.next({ title: this.title, classStr: this.classStr });
}, 1000)
}
render() {
return <div>NgerDemoAdminWelcomePage</div>
return <div>
<div className="classStr">
{"title"}
</div>
</div>
}
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@
"docker": "docker-compose up -d",
"start": "npm run cli start koa",
"build": "npm run cli build",
"platformBrowserBuild": "ts-node -r tsconfig-paths/register packages/nger-cli/lib/bin.ts build prod -n nger-platform-browser",
"build:platform:browser": "ts-node -r tsconfig-paths/register packages/nger-cli/lib/bin.ts build prod -n nger-platform-browser",
"build:nger:core": "ts-node -r tsconfig-paths/register packages/nger-cli/lib/bin.ts build prod -n nger-core",
"dev": "ts-node -r tsconfig-paths/register packages/nger-cli/lib/bin.ts dev",
"admin:build": "ts-node -r tsconfig-paths/register packages/nger-cli/lib/bin.ts build admin",
"admin:dev": "ts-node -r tsconfig-paths/register packages/nger-cli/lib/bin.ts build admin --watch",
Expand Down
6 changes: 4 additions & 2 deletions packages/nger-compiler-preact/lib/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import {
NgerCompilerBabel,
NgerCompilerNgMetadata,
metadataCache,
hasHandlerFileCache
hasHandlerFileCache,
componentRenderTransformerFactory
} from 'nger-compiler'
import { Injector } from 'nger-di'
import { relative, extname, join } from 'path';
Expand All @@ -26,7 +27,8 @@ export const preactTask: Task = async (file: string, opt: string, injector: Inje
const code = babel.compile(file, {
transformers: {
before: [
await componentTransformerFactory(file, injector)
await componentTransformerFactory(file, injector),
componentRenderTransformerFactory
]
}
});
Expand Down
9 changes: 6 additions & 3 deletions packages/nger-compiler/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import { NgerCompilerRollup } from './ts/rollup'
import { NgerCompilerNgTemplate } from './html/ng'
import { NgerCompilerCid } from './helper/cid'
import { NgerCompilerNgMetadata } from './helper/ng_metadata'
import { controllerPropertyTransformerFactory, hasPropertyMetadata } from './transformer_factorys/controller'
import { controllerPropertyTransformerFactory, hasMetadata } from './transformer_factorys/controller'
import { componentRenderTransformerFactory } from './transformer_factorys/component'

import { WATCH_TASK, Task } from './tokens/watch_task'
import { NgerCompilerBootstrap, metadataCache, hasHandlerFileCache, templateCache } from './bootstrap'
import { NgModuleBootstrap } from 'nger-core'
Expand All @@ -27,10 +29,11 @@ export {
controllerPropertyTransformerFactory,
WATCH_TASK,
Task,
hasPropertyMetadata,
hasMetadata,
metadataCache,
hasHandlerFileCache,
templateCache
templateCache,
componentRenderTransformerFactory
}
const provides: StaticProvider[] = [
...styleProviders,
Expand Down
55 changes: 55 additions & 0 deletions packages/nger-compiler/lib/transformer_factorys/component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import ts, { TransformationContext, Transformer } from 'typescript'
import {hasMetadata} from './controller';
export const componentRenderTransformerFactory = (context: TransformationContext): Transformer<ts.SourceFile> => {
return (node: ts.SourceFile): ts.SourceFile => {
node.statements = ts.createNodeArray(
node.statements.map((node: ts.Statement) => {
if (ts.isImportDeclaration(node)) {
return node;
} else if (ts.isClassDeclaration(node)) {
if(hasMetadata(node.decorators,['Page','Component'])){
return ts.createClassDeclaration(
node.decorators,
node.modifiers,
node.name,
node.typeParameters,
node.heritageClauses,
node.members.map(member => {
if (ts.isMethodDeclaration(member)) {
if(ts.isIdentifier(member.name)){
if(member.name.text === 'render'){
if(member.parameters.length===0){
return ts.createMethod(
member.decorators,
member.modifiers,
member.asteriskToken,
member.name,
member.questionToken,
member.typeParameters,
ts.createNodeArray([
ts.createParameter(undefined,undefined,undefined,'h')
]),
member.type,
member.body
)
}
}
}
}
return member;
}).filter(node => !!node)
)
}
return node;
} else {
return node;
}
})
)
return node;
}
}

function needReplaceRender(){

}
8 changes: 4 additions & 4 deletions packages/nger-compiler/lib/transformer_factorys/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const controllerPropertyTransformerFactory = (context: TransformationCont
node.heritageClauses,
node.members.map(member => {
if (ts.isMethodDeclaration(member)) {
const needReplace = hasPropertyMetadata(member.decorators);
const needReplace = hasMetadata(member.decorators);
if (needReplace) {
return ts.createProperty(
member.decorators,
Expand All @@ -26,7 +26,7 @@ export const controllerPropertyTransformerFactory = (context: TransformationCont
)
}
} else if (ts.isPropertyDeclaration(member)) {
const needReplace = hasPropertyMetadata(member.decorators);
const needReplace = hasMetadata(member.decorators);
if (needReplace) return member;
} else if (ts.isConstructorDeclaration(member)) { }
}).filter(node => !!node)
Expand All @@ -39,7 +39,7 @@ export const controllerPropertyTransformerFactory = (context: TransformationCont
return node;
}
}
export function hasPropertyMetadata(nodes: ts.NodeArray<ts.Decorator>, decorators: string[] = ['Get', 'Post']) {
export function hasMetadata(nodes: ts.NodeArray<ts.Decorator>, decorators: string[] = ['Get', 'Post']) {
const item = nodes && nodes.find(node => {
if (ts.isDecorator(node)) {
if (ts.isCallExpression(node.expression)) {
Expand All @@ -52,4 +52,4 @@ export function hasPropertyMetadata(nodes: ts.NodeArray<ts.Decorator>, decorator
return false;
})
return !!item;
}
}
30 changes: 7 additions & 23 deletions packages/nger-core/lib/platform/change_detector_ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,8 @@ import { Injector } from 'nger-di'
import { NgModuleRef } from './ng_module_ref'
import { ComponentRef } from './component_ref'
import { ComponentFactory } from './component_factory'
export abstract class ChangeDetectorRef {
abstract markForCheck(): void;
abstract detach(): void;
abstract detectChanges(): void;
abstract checkNoChanges(): void;
abstract reattach(): void;
export abstract class ChangeDetectorRef<T = any> {
abstract next(that: Partial<T>): void;
}
export abstract class ViewRef extends ChangeDetectorRef {
abstract destroy(): void;
Expand Down Expand Up @@ -61,24 +57,12 @@ export abstract class ViewContainerRef {
abstract remove(index?: number): void;
abstract detach(index?: number): ViewRef | null;
}
import { Subject } from 'rxjs'
export class DefaultChangeDetectorRef extends ChangeDetectorRef {
constructor(public subject: Subject<any>) {
import { BehaviorSubject } from 'rxjs'
export class DefaultChangeDetectorRef<T = any> extends ChangeDetectorRef<T> {
constructor(public subject: BehaviorSubject<any>) {
super();
}
markForCheck(): void {
this.subject.next();
}
detach(): void {
this.subject.next();
}
detectChanges(): void {
this.subject.next();
}
checkNoChanges(): void {
this.subject.next();
}
reattach(): void {
this.subject.next();
next(that: Partial<T>): void {
this.subject.next(that);
}
}
39 changes: 22 additions & 17 deletions packages/nger-core/lib/platform/component_factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,10 @@ import { ComponentClassAst, ComponentOptions } from '../decorators/component';

import { ChangeDetectorRef, DefaultChangeDetectorRef } from './change_detector_ref';
import { InputMetadataKey, InputPropertyAst } from '../decorators/input';
import { Subject } from 'rxjs';
import { BehaviorSubject } from 'rxjs';
import { handlerTypeContextToParams } from './createStaticProvider'
// 这个是编译后的模板文件
export const ComponentTemplateToken = new InjectionToken<string>(`ComponentTemplateToken`);
// 这个是编译后的样式文件
export const ComponentStyleToken = new InjectionToken<string>(`ComponentStyleToken`);
// 这个是编译后的json文件
export const ComponentPropToken = new InjectionToken<object>(`ComponentPropToken`);
// 这个是样式挂载文件
export const StyleRef = new InjectionToken<HTMLStyleElement>(`StyleRef`);

export type Render = (injector: Injector) => <T>(type: any, props: any, ...children: any[]) => T;
export const RENDER = new InjectionToken<Render>(`RENDER`)
export interface ComponentCreator {
(_context: TypeContext): any;
}
Expand Down Expand Up @@ -86,7 +79,6 @@ export class ComponentFactory<C> {
injector: Injector,
ngModule?: NgModuleRef<any>
): ComponentRef<C> {
const { target } = this._context;
// 新建一个
// Component,Directive,Pipe每次取都要创建
// Page/Controller单例
Expand All @@ -95,7 +87,7 @@ export class ComponentFactory<C> {
// const customElementRegistry = injector.get(CustomElementRegistry);
// customElementRegistry.define(this)
// 这个是数据监控器
const $ngOnChange = new Subject();
const $ngOnChange = new BehaviorSubject({});
const changeDetector = new DefaultChangeDetectorRef($ngOnChange)
const currentInjector = injector.create([{
provide: this.componentType,
Expand All @@ -104,13 +96,15 @@ export class ComponentFactory<C> {
const that = this;
const proxy = new Proxy(instance as any, {
set(target: any, p: PropertyKey, value: any, receiver: any) {
target[p] = value;
// 判断是否是@Input
const input = that.inputs.map(it => it.propName === p);
if (input) {
// 这里应该有数据拦截之类的东西,先todo吧
changeDetector.markForCheck();
$ngOnChange.next({
[`${p as string}`]: value
});
}
target[p] = value;
return true;
}
});
Expand All @@ -125,13 +119,24 @@ export class ComponentFactory<C> {
provide: ChangeDetectorRef,
useValue: changeDetector,
deps: []
}], target.name);
let instance = currentInjector.get(target) as C;
}], this.componentType.name);
// 是一个proxy 外部赋值会触发更新,内部赋值需要手动更新
let instance = currentInjector.get(this.componentType) as C;
const init = {};
this.inputs.map(input=>{
init[input.templateName] = instance[input.propName]
});
$ngOnChange.next(init);
// 解析一些属性并赋值
const parserVisitor = currentInjector.get(ParserVisitor);
this._context.injector = currentInjector;
parserVisitor.parse(instance, this._context);
// 设置代理
return new ComponentRef(currentInjector, instance, changeDetector, target, $ngOnChange);
const ref = new ComponentRef(currentInjector, instance, changeDetector, this.componentType as any, $ngOnChange);
ref.injector.setStatic([{
provide: ComponentRef,
useValue: ref
}])
return ref;
}
}
2 changes: 1 addition & 1 deletion packages/nger-core/lib/platform/component_ref.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injector, Type } from 'nger-di'
import { ChangeDetectorRef } from './change_detector_ref';
import { Component, ComponentOptions } from '../decorators/component'
import { Component } from '../decorators/component'
// 这个是真实的组件 P代表react中的Props,S代表State
// 这个是为了更好的融合react/preact才加上的
import { Subject } from 'rxjs'
Expand Down
4 changes: 2 additions & 2 deletions packages/nger-core/lib/platform/platform_core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import { ApplicationRef } from './application_ref'
import { ComponentCreator } from './component_factory'
import { PLATFORM_INITIALIZER } from './application_tokens'
import { NGER_CONFIG, INgerConfig } from '../sdk/nger-config'
import { Subject } from 'rxjs'
export const topSubject = new Subject();
import { BehaviorSubject } from 'rxjs'
export const topSubject = new BehaviorSubject({});
export const platformCore = createPlatformFactory(null, 'core', [{
provide: APP_INITIALIZER,
useValue: () => { },
Expand Down
2 changes: 1 addition & 1 deletion packages/nger-dom/lib/component-factory-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,6 @@ export class ComponentNgElementStrategy<T> implements NgElementStrategy {
return;
}
this.callNgOnChanges();
this.componentRef!.changeDetectorRef.detectChanges();
// this.componentRef!.changeDetectorRef.detectChanges();
}
}
23 changes: 9 additions & 14 deletions packages/nger-platform-browser/lib/application.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// 负责挂载到dom 如果是小程序 可设为空
import { ApplicationRef, ComponentFactory, ComponentRef, ElementRef, ComponentFactoryResolver, ComponentMetadataKey } from 'nger-core'
import { ApplicationRef, ComponentFactory, ComponentRef, RENDER,ElementRef, ComponentFactoryResolver, ComponentMetadataKey } from 'nger-core'
import { Injector, Type, InjectFlags } from 'nger-di'
const { render, h } = require('preact');
export function ngerRender(injector: Injector) {
Expand All @@ -20,16 +20,15 @@ export function ngerCreateElement(injector: Injector) {
const resolver = injector.get(ComponentFactoryResolver)
const factory = resolver.resolveComponentFactory(tag)
const ref = factory.create(injector);
if (ref) { }
if (ref) {
(ref.instance as any).render(ngerCreateElement(ref.injector))
}
}
}
}
(window as any).h = (injector: Injector) => (tag, attr, ...children) => {
if (typeof tag === 'string') {
} else {

}
};
(window as any).h = h;

export class BrowserApplicationRef extends ApplicationRef {
root = document.getElementById('app') as HTMLDivElement;
constructor(injector: Injector) {
Expand All @@ -52,13 +51,9 @@ export class BrowserApplicationRef extends ApplicationRef {
//这里渲染preact
if (ref.instance.render) {
const tpl = ref.instance.render.bind(ref.instance);
const res = tpl()
render(res, parent.nativeElement)
// 更新试图,后面有可能会自己实现
ref.$ngOnChange && ref.$ngOnChange.subscribe(() => {
const res = tpl()
render(res, parent.nativeElement, parent.nativeElement.lastElementChild)
});
const h = ref.injector.get(RENDER)
const element = tpl(h(ref.injector));
parent.nativeElement.appendChild(element)
super.attachView(ref, injector);
const nowTime = new Date().getTime();
const totalTime = nowTime - (window as any).nger.startTime
Expand Down
Loading

0 comments on commit 53cbdc6

Please sign in to comment.