Commit eedc3d22 authored by rockyl's avatar rockyl

mvvm实现

parent 43f8406e
This diff is collapsed.
This diff is collapsed.
{"id":"engine","url":"engine.85a610a71df748fd9a6ece34f456a06e8f3f1b63.js"} {"id":"engine","url":"engine.210e93fc8ecfcb27da00c77582649b96949d28c3.js"}
\ No newline at end of file \ No newline at end of file
{ {
"name": "aaaa", "name": "zeroing-engine",
"version": "1.0.0", "version": "0.1.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"types": "index.d.ts", "types": "index.d.ts",
......
function getPxToken(callback) {
if (window['ohjaiohdf']) {
var xhr = new XMLHttpRequest();
xhr.open('get', 'getToken', true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
var response = JSON.parse(xhr.response);
if (response.success) {
window.eval(response.data);
callback(null, window['ohjaiohdf']());
} else {
callback('state invalid');
}
}
};
xhr.onerror = function (e) {
failedCallback();
};
xhr.onloadend = function () {
if (xhr.status === 404) {
failedCallback();
}
};
xhr.send();
} else {
callback('need login');
}
function failedCallback() {
callback('net error');
}
}
...@@ -423,11 +423,11 @@ export default class Container extends DisplayObject { ...@@ -423,11 +423,11 @@ export default class Container extends DisplayObject {
} }
} }
if(this._transform === this.transform && isUI(this) && this._lastLocalID !== this.transform.localID){ /*if(this._transform === this.transform && isUI(this) && this._lastLocalID !== this.transform.localID){
this._lastLocalID = this.transform.localID; this._lastLocalID = this.transform.localID;
//console.log(this.name, this.instanceId , 'dirty!'); //console.log(this.name, this.instanceId , 'dirty!');
this.stage.layoutInvalid = true; this.stage.layoutInvalid = true;
} }*/
} }
/** /**
...@@ -699,7 +699,7 @@ export default class Container extends DisplayObject { ...@@ -699,7 +699,7 @@ export default class Container extends DisplayObject {
if (this._width !== value) { if (this._width !== value) {
//子类有用,有_width,才需设置scaleX //子类有用,有_width,才需设置scaleX
this._width = value; this._width = value;
if(this.stage) this.stage.layoutInvalid = true; //if (this.stage) this.stage.layoutInvalid = true;
this.dispatchEvent(Event.RESIZE); this.dispatchEvent(Event.RESIZE);
} }
} }
...@@ -722,7 +722,7 @@ export default class Container extends DisplayObject { ...@@ -722,7 +722,7 @@ export default class Container extends DisplayObject {
// } // }
if (this._height !== value) { if (this._height !== value) {
this._height = value; this._height = value;
if(this.stage) this.stage.layoutInvalid = true; //if (this.stage) this.stage.layoutInvalid = true;
this.dispatchEvent(Event.RESIZE); this.dispatchEvent(Event.RESIZE);
} }
} }
...@@ -730,8 +730,10 @@ export default class Container extends DisplayObject { ...@@ -730,8 +730,10 @@ export default class Container extends DisplayObject {
clone(withEvents = false, withScripts = false) { clone(withEvents = false, withScripts = false) {
let target = this.constructor.apply(Object.create(this.constructor.prototype)); let target = this.constructor.apply(Object.create(this.constructor.prototype));
const {name, properties, events, scripts} = this['__originConfig']; const originConfig = this['__originConfig'];
const {name, properties, events, scripts} = originConfig;
target.name = name; target.name = name;
target['__originConfig'] = originConfig;
injectProperties(target, properties); injectProperties(target, properties);
if (withScripts) { if (withScripts) {
...@@ -755,6 +757,20 @@ export default class Container extends DisplayObject { ...@@ -755,6 +757,20 @@ export default class Container extends DisplayObject {
return target; return target;
} }
get $store() {
let p = this;
while (p.parent) {
p = p.parent;
if (p['$isViewRoot']) {
break;
}
}
if (p) {
return p['$_store'];
}
}
//全局遍历 //全局遍历
/** /**
* @method _getElementsByName * @method _getElementsByName
......
...@@ -83,32 +83,42 @@ export class FloatDisplay extends DisplayObject { ...@@ -83,32 +83,42 @@ export class FloatDisplay extends DisplayObject {
} }
}); });
s.addEventListener(Event.ADDED_TO_STAGE, function (e: Event) { s.addEventListener(Event.ADDED_TO_STAGE, function (e: Event) {
if(!container){ this.addHtmlElement();
container = document.createElement('div'); }, s);
container.style.position = "absolute";
container.style.left = "0";
container.style.top = "0";
container.style.fontSize = '30px';
container.style.lineHeight = 'normal';
s.stage.rootDiv.appendChild(container);//, s.stage.rootDiv.childNodes[0]
}
if (s._htmlElement) {
let style = s._htmlElement.style;
if (!s._isAdded) {
s._isAdded = true;
container.appendChild(s._htmlElement);
s.stage["_floatDisplayList"].push(s);
} else {
if (s._htmlElement && s.visible) {
style.display = "block";
}
}
}
});
this._transformID = -1; this._transformID = -1;
} }
addHtmlElement() {
let s = this;
if(!s.stage){
return;
}
if (!container) {
container = document.createElement('div');
container.style.position = "absolute";
container.style.left = "0";
container.style.top = "0";
container.style.fontSize = '30px';
container.style.lineHeight = 'normal';
s.stage.rootDiv.appendChild(container);//, s.stage.rootDiv.childNodes[0]
}
if (s._htmlElement) {
let style = s._htmlElement.style;
if (!s._isAdded) {
s._isAdded = true;
container.appendChild(s._htmlElement);
s.stage["_floatDisplayList"].push(s);
} else {
if (s._htmlElement && s.visible) {
style.display = "block";
}
}
}
}
get htmlElement() { get htmlElement() {
return this._htmlElement; return this._htmlElement;
} }
...@@ -126,7 +136,7 @@ export class FloatDisplay extends DisplayObject { ...@@ -126,7 +136,7 @@ export class FloatDisplay extends DisplayObject {
* @param {HtmlElement} htmlElement 需要封装起来的html元素的引用。你可以通过这个引用来调用或设置此元素自身的属性方法和事件,甚至是样式 * @param {HtmlElement} htmlElement 需要封装起来的html元素的引用。你可以通过这个引用来调用或设置此元素自身的属性方法和事件,甚至是样式
*/ */
protected init(htmlElement: any): void { protected init(htmlElement: any): void {
if(!htmlElement){ if (!htmlElement) {
return; return;
} }
let s = this; let s = this;
...@@ -160,6 +170,8 @@ export class FloatDisplay extends DisplayObject { ...@@ -160,6 +170,8 @@ export class FloatDisplay extends DisplayObject {
s._localBoundsSelf.width = w; s._localBoundsSelf.width = w;
s._localBoundsSelf.height = h; s._localBoundsSelf.height = h;
s._htmlElement = she; s._htmlElement = she;
this.addHtmlElement();
} }
/** /**
......
...@@ -115,11 +115,6 @@ export class Stage extends Container { ...@@ -115,11 +115,6 @@ export class Stage extends Container {
*/ */
private static _stageList: any = {}; private static _stageList: any = {};
/**
* 布局失效
*/
layoutInvalid: boolean = false;
/** /**
* 是否暂停 * 是否暂停
* @property pause * @property pause
...@@ -438,7 +433,7 @@ export class Stage extends Container { ...@@ -438,7 +433,7 @@ export class Stage extends Container {
s.dispatchEvent(Event.ON_INIT_STAGE); s.dispatchEvent(Event.ON_INIT_STAGE);
// } // }
}, 100); }, 100);
let rc = canvas;//s.rootDiv; let rc = s.rootDiv; //canvas
let mouseEvent = s.onMouseEvent.bind(s); let mouseEvent = s.onMouseEvent.bind(s);
//鼠标事件 //鼠标事件
if (osType != "pc") { if (osType != "pc") {
...@@ -648,8 +643,10 @@ export class Stage extends Container { ...@@ -648,8 +643,10 @@ export class Stage extends Container {
cp = new Point(); cp = new Point();
} }
let rootDiv = s.rootDiv;
let doc = document.documentElement; let doc = document.documentElement;
let box = points[o].target.getBoundingClientRect(); let box = rootDiv.getBoundingClientRect();//points[o].target
console.log(box.y);
let left = box.left + window.pageXOffset - doc.clientLeft; let left = box.left + window.pageXOffset - doc.clientLeft;
let top = box.top + window.pageYOffset - doc.clientTop; let top = box.top + window.pageYOffset - doc.clientTop;
cp.x = (points[o].pageX - left) * devicePixelRatio; cp.x = (points[o].pageX - left) * devicePixelRatio;
...@@ -1016,14 +1013,6 @@ export class Stage extends Container { ...@@ -1016,14 +1013,6 @@ export class Stage extends Container {
} }
} }
afterUpdateTransform() {
/*this.calculateBounds();
if (this.layoutInvalid) {
this.dispatchEvent(Event.LAYOUT_INVALID);
this.layoutInvalid = false;
}*/
}
public destroy(): void { public destroy(): void {
let s = this; let s = this;
Stage.removeUpdateObj(s); Stage.removeUpdateObj(s);
......
...@@ -134,8 +134,6 @@ export default class CanvasRenderer extends SystemRenderer { ...@@ -134,8 +134,6 @@ export default class CanvasRenderer extends SystemRenderer {
displayObject.updateTransform(); displayObject.updateTransform();
displayObject.parent = cacheParent; displayObject.parent = cacheParent;
displayObject.stage && displayObject.stage.afterUpdateTransform();
//初始化上下文状态 //初始化上下文状态
context.save(); context.save();
context.setTransform(1, 0, 0, 1, 0, 0); context.setTransform(1, 0, 0, 1, 0, 0);
......
...@@ -179,8 +179,6 @@ export class WebglRenderer extends SystemRenderer { ...@@ -179,8 +179,6 @@ export class WebglRenderer extends SystemRenderer {
displayObject.updateTransform(); displayObject.updateTransform();
displayObject.parent = cacheParent; displayObject.parent = cacheParent;
displayObject.stage && displayObject.stage.afterUpdateTransform();
//绑定渲染对象,没有则是默认root //绑定渲染对象,没有则是默认root
this.bindRenderTexture(renderTexture, transform); this.bindRenderTexture(renderTexture, transform);
......
...@@ -7,14 +7,16 @@ import {StackContainer} from "./StackContainer"; ...@@ -7,14 +7,16 @@ import {StackContainer} from "./StackContainer";
import {loadAssets} from "./assets-manager"; import {loadAssets} from "./assets-manager";
import {instantiate} from "./view-interpreter"; import {instantiate} from "./view-interpreter";
import {dataCenter, DataCenter} from "./data-center"; import {dataCenter, DataCenter} from "./data-center";
import {setProcessMetaLibs} from "../behavior-runtime"; import {setProcessMetaLibs} from "../behavior-runtime/index";
import {Tween} from "../../2d/tween"; import {Tween} from "../../2d/tween/index";
import {Rect} from "./nodes"; import {Rect} from "./nodes/index";
import {injectEnv} from "./enviroment"; import {injectEnv} from "./enviroment";
import {Toast} from "./Toast"; import {Toast} from "./Toast";
import {arrayFind} from "../utils"; import {arrayFind} from "../utils/index";
import {registerCustomModules, registerScripts} from "..";
import {Node} from "./nodes/Node"; import {Node} from "./nodes/Node";
import {bind, createStore} from "./mvvm/index";
import {safeEval} from "../utils/utils";
import {registerCustomModules} from "./custom-module";
/** /**
* 游戏舞台 * 游戏舞台
...@@ -62,6 +64,7 @@ export class GameStage extends Node { ...@@ -62,6 +64,7 @@ export class GameStage extends Node {
this._popupContainer.name = 'popup-container'; this._popupContainer.name = 'popup-container';
this._popupContainer.addEventListener('change', this.onPopupContainerChange, this); this._popupContainer.addEventListener('change', this.onPopupContainerChange, this);
} }
/** /**
...@@ -180,6 +183,23 @@ export class GameStage extends Node { ...@@ -180,6 +183,23 @@ export class GameStage extends Node {
let viewConfig = this.getViewConfigByName(name); let viewConfig = this.getViewConfigByName(name);
if (viewConfig) { if (viewConfig) {
view = instantiate(viewConfig); view = instantiate(viewConfig);
let store = {};
if(viewConfig.store){
const {exp, computed} = viewConfig.store;
store = createStore(exp, computed);
}
view['$isViewRoot'] = true;
view['$_store'] = store;
/*let label = view.children[0];
label['z-for'] = 'item in list';*/
console.time('bind');
bind(store, view);
console.timeEnd('bind');
if (cache) { if (cache) {
this._viewCache[name] = view; this._viewCache[name] = view;
} }
......
/**
* Created by Raykid on 2016/12/16.
*/
import {IAres, Compiler, AresOptions, IWatcher, WatcherCallback, AresCommandData} from "./Interfaces";
import {Mutator} from "./Mutator";
import {Watcher} from "./Watcher";
import {CommandContext, Command, commands} from "./Commands"
export const defaultCmdRegExp:RegExp = /^(data\-)?a[\-_](\w+)([:\$](.+))?$/;
/**
* 将数据模型和视图进行绑定
* @param data
* @param compiler 视图解析器,不同类型的视图需要使用不同的解析器解析后方可使用
* @param options 一些额外参数
* @returns {IAres} 绑定实体对象
*/
export function bind(data:any, compiler:Compiler, options?:AresOptions):IAres
{
return new Ares(data, compiler, options);
}
export class Ares implements IAres
{
private _data:any;
private _compiler:Compiler;
private _options:any;
/** 获取ViewModel */
public get data():any
{
return this._data;
}
/** 获取编译器 */
public get compiler():Compiler
{
return this._compiler;
}
public constructor(data:any, compiler:Compiler, options?:AresOptions)
{
// 记录变异对象
this._data = Mutator.mutate(data);
this._compiler = compiler;
this._options = options;
// 初始化Compiler
this._compiler.init(this);
// 调用回调
if(this._options && this._options.inited)
{
this._options.inited.call(this._data, this);
}
}
public createWatcher(target:any, exp:string, scope:any, callback:WatcherCallback):IWatcher
{
return new Watcher(this, target, exp, scope, callback);
}
/**
* 解析表达式成为命令数据
* @param key 属性名,合法的属性名应以a-或a_开头,以:或$分隔主命令和子命令
* @param value 属性值,如果属性名合法则会被用来作为表达式的字符串
* @param cmdRegExp 可选,如果不传则使用默认的命令正则表达式解析命令
* @return {CommandData|null} 命令数据,如果不是命令则返回null
*/
public parseCommand(key:string, value:string, cmdRegExp?:RegExp):AresCommandData
{
var result:RegExpExecArray = (cmdRegExp || defaultCmdRegExp).exec(key);
if(!result) return null;
// 取到key
var key:string = result[0];
// 取到命令名
var cmdName:string = result[2];
// 取到命令字符串
var exp:string = value;
// 取到子命令名
var subCmd:string = result[4] || "";
// 返回结构体
return {
cmdName: cmdName,
subCmd: subCmd,
propName: key,
exp: exp
};
}
/**
* 测试是否是通用命令
* @param data 命令数据
* @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令
*/
public testCommand(data:AresCommandData):boolean
{
// 非空判断
if(!data) return false;
// 取到通用命令
var cmd:Command = commands[data.cmdName];
return (cmd != null);
}
/**
* 执行通用命令,如果该表达式是通用命令则直接执行,否则什么都不做
* @param data 命令数据
* @param target 目标对象
* @param scope 变量作用域
* @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令
*/
public execCommand(data:AresCommandData, target:any, scope:any):boolean
{
// 非空判断
if(!data || !scope) return false;
// 取到通用命令
var cmd:Command = commands[data.cmdName];
// 没找到命令就返回false
if(!cmd) return false;
// 找到命令了,执行之
cmd({
target: target,
scope: scope,
entity: this,
data: data
});
return true;
}
}
\ No newline at end of file
...@@ -2,15 +2,15 @@ ...@@ -2,15 +2,15 @@
* Created by Raykid on 2017/7/19. * Created by Raykid on 2017/7/19.
*/ */
import {IAres, AresCommandData} from "./Interfaces" import {IZri, ZriCommandData} from "./Interfaces"
import {runExp} from "./Utils" import {runExp} from "./Utils"
export interface CommandContext export interface CommandContext
{ {
target:any; target:any;
scope:any; scope:any;
entity:IAres; entity:IZri;
data:AresCommandData; data:ZriCommandData;
} }
export interface Command export interface Command
......
...@@ -4,32 +4,27 @@ ...@@ -4,32 +4,27 @@
import {Watcher} from "./Watcher"; import {Watcher} from "./Watcher";
export class Dep export class Dep {
{ private _map: { [uid: number]: Watcher } = {};
private _map:{[uid:number]:Watcher} = {};
/** /**
* 添加数据变更订阅者 * 添加数据变更订阅者
* @param watcher 数据变更订阅者 * @param watcher 数据变更订阅者
*/ */
public watch(watcher:Watcher):void public watch(watcher: Watcher): void {
{ if (!this._map[watcher.uid]) {
if(!this._map[watcher.uid]) this._map[watcher.uid] = watcher;
{ }
this._map[watcher.uid] = watcher; }
}
}
/** /**
* 数据变更,通知所有订阅者 * 数据变更,通知所有订阅者
* @param extra 可能的额外数据 * @param extra 可能的额外数据
*/ */
public notify(extra?:any):void public notify(extra?: any): void {
{ for (var uid in this._map) {
for(var uid in this._map) var watcher: Watcher = this._map[uid];
{ watcher.update(extra);
var watcher:Watcher = this._map[uid]; }
watcher.update(extra); }
}
}
} }
\ No newline at end of file
...@@ -7,9 +7,9 @@ export interface Compiler ...@@ -7,9 +7,9 @@ export interface Compiler
root:any; root:any;
/** /**
* 初始化编译器 * 初始化编译器
* @param entity Ares实例 * @param entity Zri实例
*/ */
init(entity:IAres):void; init(entity:IZri):void;
/** /**
* 编译方法 * 编译方法
* @param target 要编译的显示节点 * @param target 要编译的显示节点
...@@ -18,7 +18,7 @@ export interface Compiler ...@@ -18,7 +18,7 @@ export interface Compiler
compile(target:any, scope:any):void; compile(target:any, scope:any):void;
} }
export interface IAres export interface IZri
{ {
/** 获取ViewModel */ /** 获取ViewModel */
data:any; data:any;
...@@ -39,13 +39,13 @@ export interface IAres ...@@ -39,13 +39,13 @@ export interface IAres
* @param value 属性值,如果属性名合法则会被用来作为表达式的字符串 * @param value 属性值,如果属性名合法则会被用来作为表达式的字符串
* @return {CommandData|null} 命令数据,如果不是命令则返回null * @return {CommandData|null} 命令数据,如果不是命令则返回null
*/ */
parseCommand(key:string, value:string):AresCommandData; parseCommand(key:string, value:string):ZriCommandData;
/** /**
* 测试是否是通用命令 * 测试是否是通用命令
* @param data 命令数据 * @param data 命令数据
* @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令 * @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令
*/ */
testCommand(data:AresCommandData):boolean; testCommand(data:ZriCommandData):boolean;
/** /**
* 执行通用命令,如果该表达式是通用命令则直接执行,否则什么都不做 * 执行通用命令,如果该表达式是通用命令则直接执行,否则什么都不做
* @param data 命令数据 * @param data 命令数据
...@@ -53,12 +53,12 @@ export interface IAres ...@@ -53,12 +53,12 @@ export interface IAres
* @param scope 变量作用域 * @param scope 变量作用域
* @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令 * @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令
*/ */
execCommand(data:AresCommandData, target:any, scope:any):boolean execCommand(data:ZriCommandData, target:any, scope:any):boolean
} }
export interface AresOptions export interface ZriOptions
{ {
inited?:(entity?:IAres)=>void; inited?:(entity?:IZri)=>void;
} }
export interface IWatcher export interface IWatcher
...@@ -82,7 +82,7 @@ export interface WatcherCallback ...@@ -82,7 +82,7 @@ export interface WatcherCallback
(newValue?:any, oldValue?:any, extra?:any):void; (newValue?:any, oldValue?:any, extra?:any):void;
} }
export interface AresCommandData export interface ZriCommandData
{ {
/** 主命令名 */ /** 主命令名 */
cmdName:string; cmdName:string;
...@@ -92,4 +92,4 @@ export interface AresCommandData ...@@ -92,4 +92,4 @@ export interface AresCommandData
propName:string; propName:string;
/** 表达式 */ /** 表达式 */
exp:string; exp:string;
} }
\ No newline at end of file
...@@ -5,143 +5,134 @@ ...@@ -5,143 +5,134 @@
import {Watcher} from "./Watcher"; import {Watcher} from "./Watcher";
import {Dep} from "./Dep"; import {Dep} from "./Dep";
export class Mutator export class Mutator {
{ // 记录数组中会造成数据更新的所有方法名
// 记录数组中会造成数据更新的所有方法名 private static _arrMethods: string[] = [
private static _arrMethods:string[] = [ "push",
"push", "pop",
"pop", "unshift",
"unshift", "shift",
"shift", "splice",
"splice", "sort",
"sort", "reverse"
"reverse" ];
];
/** /**
* 将用户传进来的数据“变异”成为具有截获数据变更能力的数据 * 将用户传进来的数据“变异”成为具有截获数据变更能力的数据
* @param data 原始数据 * @param data 原始数据
* @returns {any} 变异后的数据 * @returns {any} 变异后的数据
*/ */
public static mutate(data:any):any public static mutate(data: any): any {
{ // 如果是简单类型,则啥也不做
// 如果是简单类型,则啥也不做 if (!data || typeof data != "object") return;
if(!data || typeof data != "object") return; // 是个复杂类型对象,但是以前变异过了就不再重做一遍了
// 是个复杂类型对象,但是以前变异过了就不再重做一遍了 if (!data.__ares_mutated__) {
if(!data.__ares_mutated__) // 针对每个内部变量都进行一次变异
{ for (var key in data) {
// 针对每个内部变量都进行一次变异 Mutator.mutateProp(data, key, data[key]);
for(var key in data) }
{ // 打一个标记表示已经变异过了
Mutator.mutateObject(data, key, data[key]); Object.defineProperty(data, "__ares_mutated__", {
} value: true,
// 打一个标记表示已经变异过了 writable: false,
Object.defineProperty(data, "__ares_mutated__", { enumerable: false,
value: true, configurable: false
writable: false, });
enumerable: false, }
configurable: false return data;
}); }
}
return data;
}
private static mutateObject(data:any, key:string, value:any):void private static mutateProp(data: any, key: string, value: any): void {
{ // 对每个复杂类型对象都要有一个对应的依赖列表
// 对每个复杂类型对象都要有一个对应的依赖列表 var dep: Dep = new Dep();
var dep:Dep = new Dep(); // 变异过程
// 变异过程 Object.defineProperty(data, key, {
Object.defineProperty(data, key, { enumerable: true,
enumerable: true, configurable: false,
configurable: false, get: () => {
get: ()=>{ // 如果Watcher.updating不是null,说明当前正在执行表达式,那么获取的变量自然是其需要依赖的
// 如果Watcher.updating不是null,说明当前正在执行表达式,那么获取的变量自然是其需要依赖的 var watcher: Watcher = Watcher.updating;
var watcher:Watcher = Watcher.updating; if (watcher) dep.watch(watcher);
if(watcher) dep.watch(watcher); // 利用闭包保存原始值
// 利用闭包保存原始值 return value;
return value; },
}, set: v => {
set: v=>{ if (v == value) return;
if(v == value) return; value = v;
value = v; // 如果是数组就走专门的数组变异方法,否则递归变异对象
// 如果是数组就走专门的数组变异方法,否则递归变异对象 if (Array.isArray(v)) Mutator.mutateArray(v, dep);
if(Array.isArray(v)) Mutator.mutateArray(v, dep); else Mutator.mutate(v);
else Mutator.mutate(v); // 触发通知
// 触发通知 dep.notify();
dep.notify(); }
} });
}); if(Array.isArray(value)){
// 递归变异 Mutator.mutateArray(value, dep);
Mutator.mutate(value); }else{
} // 递归变异
Mutator.mutate(value);
}
}
private static mutateArray(arr:any[], dep:Dep):void private static mutateArray(arr: any[], dep: Dep): void {
{ // 变异当前数组
// 变异当前数组 arr["__proto__"] = Mutator.defineReactiveArray(dep);
arr["__proto__"] = Mutator.defineReactiveArray(dep); // 遍历当前数组,将内容对象全部变异
// 遍历当前数组,将内容对象全部变异 for (var i: number = 0, len: number = arr.length; i < len; i++) {
for(var i:number = 0, len:number = arr.length; i < len; i++) Mutator.mutate(arr[i]);
{ }
Mutator.mutate(arr[i]); }
}
}
private static defineReactiveArray(dep:Dep):any[] private static defineReactiveArray(dep: Dep): any[] {
{ var proto: any[] = Array.prototype;
var proto:any[] = Array.prototype; var result: any[] = Object.create(proto);
var result:any[] = Object.create(proto); // 遍历所有方法,一个一个地变异
// 遍历所有方法,一个一个地变异 Mutator._arrMethods.forEach((method: string) => {
Mutator._arrMethods.forEach((method:string)=>{ // 利用闭包记录一个原始方法
// 利用闭包记录一个原始方法 var oriMethod: Function = proto[method];
var oriMethod:Function = proto[method]; // 开始变异
// 开始变异 Object.defineProperty(result, method, {
Object.defineProperty(result, method, { value: function (...args: any[]): any {
value: function(...args:any[]):any // 首先调用原始方法,获取返回值
{ var result: any = oriMethod.apply(this, args);
// 首先调用原始方法,获取返回值 // 数组插入项
var result:any = oriMethod.apply(this, args); var inserted: any[];
// 数组插入项 switch (method) {
var inserted:any[]; case "push":
switch(method) case "unshift":
{ inserted = args;
case "push": break
case "unshift": case "splice":
inserted = args; inserted = args.slice(2);
break break
case "splice": }
inserted = args.slice(2); // 监视数组插入项,而不是重新监视整个数组
break if (inserted && inserted.length) {
} Mutator.mutateArray(inserted, dep);
// 监视数组插入项,而不是重新监视整个数组 }
if(inserted && inserted.length) // 触发更新
{ dep.notify({method: args});
Mutator.mutateArray(inserted, dep); // 返回值
} return result;
// 触发更新 }
dep.notify({method: args}); });
// 返回值 });
return result; // 提供替换数组设置的方法,因为直接设置数组下标的方式无法变异
} Object.defineProperty(result, "$set", {
}); value: function (index: number, value: any): any {
}); // 超出数组长度默认追加到最后
// 提供替换数组设置的方法,因为直接设置数组下标的方式无法变异 if (index >= this.length) index = this.length;
Object.defineProperty(result, "$set", { return this.splice(index, 1, value)[0];
value: function(index:number, value:any):any }
{ });
// 超出数组长度默认追加到最后 // 提供替换数组移除的方法,因为直接移除的方式无法变异
if(index >= this.length) index = this.length; Object.defineProperty(result, "$remove", {
return this.splice(index, 1, value)[0]; value: function (item: any): any {
} var index = this.indexOf(item);
}); if (index > -1) return this.splice(index, 1);
// 提供替换数组移除的方法,因为直接移除的方式无法变异 return null;
Object.defineProperty(result, "$remove", { }
value: function(item:any):any });
{ return result;
var index = this.indexOf(item); }
if(index > -1) return this.splice(index, 1);
return null;
}
});
return result;
}
} }
\ No newline at end of file
...@@ -6,27 +6,27 @@ ...@@ -6,27 +6,27 @@
* @param exp 表达式 * @param exp 表达式
* @returns {Function} 创建的方法 * @returns {Function} 创建的方法
*/ */
export function createEvalFunc(exp:string):(scope:any)=>any export function createEvalFunc(exp: string): (scope: any) => any {
{ var func: (scope: any) => any;
var func:(scope:any)=>any; try {
try func = Function("scope", "with(scope){return " + exp + "}") as (scope: any) => any;
{ } catch (err) {
func = Function("scope", "with(scope){return " + exp + "}") as (scope:any)=>any; // 可能是某些版本的解释器不认识模板字符串,将模板字符串变成普通字符串
} var sepStr: string = (exp.indexOf('"') < 0 ? '"' : "'");
catch(err) // 将exp中的·替换为'
{ var reg: RegExp = /([^\\]?)`/g;
// 可能是某些版本的解释器不认识模板字符串,将模板字符串变成普通字符串 exp = exp.replace(reg, "$1" + sepStr);
var sepStr:string = (exp.indexOf('"') < 0 ? '"' : "'"); // 将exp中${...}替换为" + ... + "的形式
// 将exp中的·替换为' reg = /\$\{(.*?)\}/g;
var reg:RegExp = /([^\\]?)`/g; exp = exp.replace(reg, sepStr + "+($1)+" + sepStr);
exp = exp.replace(reg, "$1" + sepStr); // 重新生成方法并返回
// 将exp中${...}替换为" + ... + "的形式 try {
reg = /\$\{(.*?)\}/g; func = Function("scope", "with(scope){return " + exp + "}") as (scope: any) => any;
exp = exp.replace(reg, sepStr + "+($1)+" + sepStr); }catch (e) {
// 重新生成方法并返回 console.error('非法的表达式:', exp);
func = Function("scope", "with(scope){return " + exp + "}") as (scope:any)=>any; }
} }
return func; return func;
} }
/** /**
...@@ -35,9 +35,8 @@ export function createEvalFunc(exp:string):(scope:any)=>any ...@@ -35,9 +35,8 @@ export function createEvalFunc(exp:string):(scope:any)=>any
* @param scope 表达式的作用域 * @param scope 表达式的作用域
* @returns {any} 返回值 * @returns {any} 返回值
*/ */
export function evalExp(exp:string, scope:any):any export function evalExp(exp: string, scope: any): any {
{ return createEvalFunc(exp)(scope);
return createEvalFunc(exp)(scope);
} }
/** /**
...@@ -45,9 +44,8 @@ export function evalExp(exp:string, scope:any):any ...@@ -45,9 +44,8 @@ export function evalExp(exp:string, scope:any):any
* @param exp 表达式 * @param exp 表达式
* @returns {Function} 创建的方法 * @returns {Function} 创建的方法
*/ */
export function createRunFunc(exp:string):(scope:any)=>void export function createRunFunc(exp: string): (scope: any) => void {
{ return createEvalFunc("(function(){" + exp + "})()");
return createEvalFunc("(function(){" + exp + "})()");
} }
/** /**
...@@ -55,7 +53,6 @@ export function createRunFunc(exp:string):(scope:any)=>void ...@@ -55,7 +53,6 @@ export function createRunFunc(exp:string):(scope:any)=>void
* @param exp 表达式 * @param exp 表达式
* @param scope 表达式的作用域 * @param scope 表达式的作用域
*/ */
export function runExp(exp:string, scope:any):void export function runExp(exp: string, scope: any): void {
{ createRunFunc(exp)(scope);
createRunFunc(exp)(scope);
} }
\ No newline at end of file
import {IAres, IWatcher, WatcherCallback} from "./Interfaces"; import {IZri, IWatcher, WatcherCallback} from "./Interfaces";
import {createEvalFunc} from "./Utils"; import {createEvalFunc} from "./Utils";
/** /**
* Created by Raykid on 2016/12/22. * Created by Raykid on 2016/12/22.
* 数据更新订阅者,当依赖的数据有更新时会触发callback通知外面 * 数据更新订阅者,当依赖的数据有更新时会触发callback通知外面
*/ */
export class Watcher implements IWatcher export class Watcher implements IWatcher {
{ /** 记录当前正在执行update方法的Watcher引用 */
/** 记录当前正在执行update方法的Watcher引用 */ public static updating: Watcher = null;
public static updating:Watcher = null;
private static _uid:number = 0; private static _uid: number = 0;
private _uid:number; private _uid: number;
/** 获取Watcher的全局唯一ID */ /** 获取Watcher的全局唯一ID */
public get uid():number public get uid(): number {
{ return this._uid;
return this._uid; }
}
private _value:any; private _value: any;
private _entity:IAres; private _entity: IZri;
private _target:any; private _target: any;
private _exp:string; private _exp: string;
private _scope:any; private _scope: any;
private _expFunc:(scope:any)=>any; private _expFunc: (scope: any) => any;
private _callback:WatcherCallback; private _callback: WatcherCallback;
private _disposed:boolean = false; private _disposed: boolean = false;
public constructor(entity:IAres, target:any, exp:string, scope:any, callback:WatcherCallback) public constructor(entity: IZri, target: any, exp: string, scope: any, callback: WatcherCallback) {
{ // 记录entity
// 记录entity this._entity = entity;
this._entity = entity; // 生成一个全局唯一的ID
// 生成一个全局唯一的ID this._uid = Watcher._uid++;
this._uid = Watcher._uid ++; // 记录作用目标、表达式和作用域
// 记录作用目标、表达式和作用域 this._target = target;
this._target = target; this._exp = exp;
this._exp = exp; this._scope = scope;
this._scope = scope; // 将表达式和作用域解析为一个Function
// 将表达式和作用域解析为一个Function this._expFunc = createEvalFunc(exp);
this._expFunc = createEvalFunc(exp); // 记录回调函数
// 记录回调函数 this._callback = callback;
this._callback = callback; // 进行首次更新
// 进行首次更新 this.update();
this.update(); }
}
/** /**
* 获取到表达式当前最新值 * 获取到表达式当前最新值
* @returns {any} 最新值 * @returns {any} 最新值
*/ */
public getValue():any public getValue(): any {
{ if (this._disposed) return null;
if(this._disposed) return null; var value: any = null;
var value:any = null; // 记录自身
// 记录自身 Watcher.updating = this;
Watcher.updating = this; // 设置通用属性
// 设置通用属性 // 这里一定要用defineProperty将目标定义在当前节点上,否则会影响context.scope
// 这里一定要用defineProperty将目标定义在当前节点上,否则会影响context.scope Object.defineProperty(this._scope, "$root", {
Object.defineProperty(this._scope, "$root", { configurable: true,
configurable: true, enumerable: false,
enumerable: false, value: this._entity.compiler.root,
value: this._entity.compiler.root, writable: false
writable: false });
}); // 这里一定要用defineProperty将目标定义在当前节点上,否则会影响context.scope
// 这里一定要用defineProperty将目标定义在当前节点上,否则会影响context.scope Object.defineProperty(this._scope, "$target", {
Object.defineProperty(this._scope, "$target", { configurable: true,
configurable: true, enumerable: false,
enumerable: false, value: this._target,
value: this._target, writable: false
writable: false });
}); // 表达式求值
// 表达式求值 try {
try value = this._expFunc.call(this._scope, this._scope);
{ } catch (err) {
value = this._expFunc.call(this._scope, this._scope); // 输出错误日志
} console.warn("表达式求值错误\nerr: " + err.toString() + "\nexp:" + this._exp + ",scope:" + JSON.stringify(this._scope));
catch(err) }
{ // 移除通用属性
// 输出错误日志 delete this._scope["$root"];
console.warn("表达式求值错误\nerr: " + err.toString() + "\nexp:" + this._exp + ",scope:" + JSON.stringify(this._scope)); delete this._scope["$target"];
} // 移除自身记录
// 移除通用属性 Watcher.updating = null;
delete this._scope["$root"]; return value;
delete this._scope["$target"]; }
// 移除自身记录
Watcher.updating = null;
return value;
}
/** /**
* 当依赖的数据有更新时调用该方法 * 当依赖的数据有更新时调用该方法
* @param extra 可能的额外数据 * @param extra 可能的额外数据
*/ */
public update(extra?:any):void public update(extra?: any): void {
{ if (this._disposed) return;
if(this._disposed) return; var value: any = this.getValue();
var value:any = this.getValue(); if (!Watcher.isEqual(value, this._value)) {
if(!Watcher.isEqual(value, this._value)) this._callback && this._callback(value, this._value, extra);
{ this._value = Watcher.deepCopy(value);
this._callback && this._callback(value, this._value, extra); }
this._value = Watcher.deepCopy(value); }
}
}
/** 销毁订阅者 */
public dispose():void
{
if(this._disposed) return;
this._value = null;
this._target = null;
this._exp = null;
this._scope = null;
this._expFunc = null;
this._callback = null;
this._disposed = true;
}
/** /** 销毁订阅者 */
* 是否相等,包括基础类型和对象/数组的对比 public dispose(): void {
*/ if (this._disposed) return;
private static isEqual(a:any, b:any):boolean this._value = null;
{ this._target = null;
return (a == b || ( this._exp = null;
Watcher.isObject(a) && Watcher.isObject(b) this._scope = null;
? JSON.stringify(a) == JSON.stringify(b) this._expFunc = null;
: false this._callback = null;
)); this._disposed = true;
} }
/** /**
* 是否为对象(包括数组、正则等) * 是否相等,包括基础类型和对象/数组的对比
*/ */
private static isObject(obj:any):boolean private static isEqual(a: any, b: any): boolean {
{ return (a == b || (
return (obj && typeof obj == "object"); Watcher.isObject(a) && Watcher.isObject(b)
} ? JSON.stringify(a) == JSON.stringify(b)
: false
));
}
/** /**
* 复制对象,若为对象则深度复制 * 是否为对象(包括数组、正则等)
*/ */
private static deepCopy(from:any):any private static isObject(obj: any): boolean {
{ return (obj && typeof obj == "object");
if (Watcher.isObject(from)) }
{
// 复杂类型对象,先字符串化,再对象化 /**
return JSON.parse(JSON.stringify(from)); * 复制对象,若为对象则深度复制
} */
else private static deepCopy(from: any): any {
{ if (Watcher.isObject(from)) {
// 基本类型对象,直接返回之 // 复杂类型对象,先字符串化,再对象化
return from; return JSON.parse(JSON.stringify(from));
} } else {
} // 基本类型对象,直接返回之
return from;
}
}
} }
\ No newline at end of file
/**
* Created by rockyl on 2020-03-19.
*/
import {IZri, Compiler, ZriOptions, IWatcher, WatcherCallback, ZriCommandData} from "./Interfaces";
import {Mutator} from "./Mutator";
import {Watcher} from "./Watcher";
import {CommandContext, Command, commands} from "./Commands"
export const defaultCmdRegExp:RegExp = /^(data\-)?z[\-_](\w+)([:\$](.+))?$/;
export class Zri implements IZri
{
private _data:any;
private _compiler:Compiler;
private _options:any;
/** 获取ViewModel */
public get data():any
{
return this._data;
}
/** 获取编译器 */
public get compiler():Compiler
{
return this._compiler;
}
public constructor(data:any, compiler:Compiler, options?:ZriOptions)
{
// 记录变异对象
this._data = Mutator.mutate(data);
this._compiler = compiler;
this._options = options;
// 初始化Compiler
this._compiler.init(this);
// 调用回调
if(this._options && this._options.inited)
{
this._options.inited.call(this._data, this);
}
}
public createWatcher(target:any, exp:string, scope:any, callback:WatcherCallback):IWatcher
{
return new Watcher(this, target, exp, scope, callback);
}
/**
* 解析表达式成为命令数据
* @param key 属性名,合法的属性名应以a-或a_开头,以:或$分隔主命令和子命令
* @param value 属性值,如果属性名合法则会被用来作为表达式的字符串
* @param cmdRegExp 可选,如果不传则使用默认的命令正则表达式解析命令
* @return {CommandData|null} 命令数据,如果不是命令则返回null
*/
public parseCommand(key:string, value:string, cmdRegExp?:RegExp):ZriCommandData
{
var result:RegExpExecArray = (cmdRegExp || defaultCmdRegExp).exec(key);
if(!result) return null;
// 取到key
var key:string = result[0];
// 取到命令名
var cmdName:string = result[2];
// 取到命令字符串
var exp:string = value;
// 取到子命令名
var subCmd:string = result[4] || "";
// 返回结构体
return {
cmdName: cmdName,
subCmd: subCmd,
propName: key,
exp: exp
};
}
/**
* 测试是否是通用命令
* @param data 命令数据
* @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令
*/
public testCommand(data:ZriCommandData):boolean
{
// 非空判断
if(!data) return false;
// 取到通用命令
var cmd:Command = commands[data.cmdName];
return (cmd != null);
}
/**
* 执行通用命令,如果该表达式是通用命令则直接执行,否则什么都不做
* @param data 命令数据
* @param target 目标对象
* @param scope 变量作用域
* @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令
*/
public execCommand(data:ZriCommandData, target:any, scope:any):boolean
{
// 非空判断
if(!data || !scope) return false;
// 取到通用命令
var cmd:Command = commands[data.cmdName];
// 没找到命令就返回false
if(!cmd) return false;
// 找到命令了,执行之
cmd({
target: target,
scope: scope,
entity: this,
data: data
});
return true;
}
}
/**
* Created by rockyl on 2020-03-19.
*/
import {DisplayObject} from "../../../2d/display/DisplayObject";
import {ZriCompiler} from "./ZriCompiler";
import {IWatcher, IZri, ZriCommandData} from "./Interfaces";
import {evalExp, runExp} from "./Utils";
import {Container} from "../../../2d/display/index";
export interface Command {
/**
* 执行命令
* @param context 命令上下文
*/
(context?: CommandContext): DisplayObject;
}
export interface CommandContext {
scope: any;
target: Container;
entity: IZri;
cmdData: ZriCommandData;
[name: string]: any;
}
export const commands: { [name: string]: Command } = {
prop: (context: CommandContext) => {
let cmdData: ZriCommandData = context.cmdData;
let target: DisplayObject = context.target;
context.entity.createWatcher(target, cmdData.exp, context.scope, (value: any) => {
if (cmdData.subCmd != "") {
target[cmdData.subCmd] = value;
} else {
for (let name in value) {
target[name] = value[name];
}
}
});
// 返回节点
return target;
},
on: (context: CommandContext) => {
let cmdData: ZriCommandData = context.cmdData;
if (cmdData.subCmd != "") {
let handler: Function = context.scope[cmdData.exp] || window[context.cmdData.exp];
if (typeof handler == "function") {
// 是函数名形式
context.target.addEventListener(cmdData.subCmd, function () {
handler.apply(this, arguments);
}, context.scope);
} else {
// 是方法执行或者表达式方式
context.target.addEventListener(cmdData.subCmd, (evt: Event) => {
// 创建一个临时的子域,用于保存参数
let scope: any = Object.create(context.scope);
scope.$event = evt;
scope.$target = context.target;
runExp(cmdData.exp, scope);
});
}
}
// 返回节点
return context.target;
},
if: (context: CommandContext) => {
let cmdData: ZriCommandData = context.cmdData;
// 记录一个是否编译过的flag
let compiled: boolean = false;
// 插入一个占位元素
let refNode: Container = new Container();
refNode.mouseChildren = refNode.mouseEnabled = false;
let parent: Container = context.target.parent;
let index: number = parent.getChildIndex(context.target);
parent.removeChildAt(index);
parent.addChildAt(refNode, index);
// 只有在条件为true时才启动编译
let watcher: IWatcher = context.entity.createWatcher(context.target, cmdData.exp, context.scope, (value: boolean) => {
// 如果refNode被从显示列表移除了,则表示该if指令要作废了
if (!refNode.parent && !context.target.parent) {
watcher.dispose();
return;
}
if (value == true) {
// 插入节点
if (!context.target.parent) {
let parent = refNode.parent;
let index: number = parent.getChildIndex(refNode);
parent.removeChild(refNode);
parent.addChildAt(context.target, index);
}
// 启动编译
if (!compiled) {
context.compiler.compile(context.target, context.scope);
compiled = true;
}
} else {
// 移除元素
if (context.target.parent) {
let parent = context.target.parent;
let index: number = parent.getChildIndex(context.target);
parent.removeChild(context.target);
parent.addChildAt(refNode, index);
}
}
});
// 返回节点
return context.target;
},
for: (context: CommandContext) => {
let cmdData: ZriCommandData = context.cmdData;
let options = evalExp(cmdData.subCmd, context.scope) || {};
let page: number = (options.page || Number.MAX_VALUE);
// 解析表达式
let reg: RegExp = /^\s*(\S+)\s+in\s+([\s\S]+?)\s*$/;
let res: RegExpExecArray = reg.exec(cmdData.exp);
if (!res) {
console.error("for命令表达式错误:" + cmdData.exp);
return;
}
let itemName: string = res[1];
let arrName: string = res[2];
// 生成一个容器替换原始模板
let index: number = context.target.parent.getChildIndex(context.target);
let parent: Container = new Container();
context.target.parent.addChildAt(parent, index);
context.target.parent.removeChild(context.target);
// 生成一个新的scope,要向其中添加属性
let forScope: any = Object.create(context.scope);
Object.defineProperty(forScope, "$forTarget", {
configurable: true,
enumerable: false,
value: context.target,
writable: false
});
// 如果有viewport命令,则将其转移至容器上
/*let viewportCmds:ZriCommandData[] = context.cmdDict["viewport"];
if(viewportCmds)
{
let viewportCmd:ZriCommandData = viewportCmds[0];
if(viewportCmd)
{
parent[viewportCmd.propName] = viewportCmd.exp;
delete context.target[viewportCmd.propName];
}
}*/
// 使用原始显示对象编译一次parent
context.compiler.compile(parent, forScope);
// 获取窗口显示范围
//let viewportHandler:ViewPortHandler = getViewportHandler(parent);
// 声明闭包数据
let isArray: boolean;
let curList: any[];
let curIndex: number;
let lastNode: DisplayObject;
// 添加订阅
let watcher: IWatcher = context.entity.createWatcher(context.target, arrName, forScope, (value: any) => {
// 如果refNode被从显示列表移除了,则表示该for指令要作废了
if (!parent.parent) {
watcher.dispose();
return;
}
// 清理原始显示
for (let i: number = parent.children.length - 1; i >= 0; i--) {
parent.removeChildAt(i).destroy();
}
// 如果是数字,构建一个数字列表
if (typeof value == "number") {
let temp: number[] = [];
for (let i: number = 0; i < value; i++) {
temp.push(i);
}
value = temp;
}
// 如果不是数组,而是字典,则转换为数组,方便中断遍历
isArray = (value instanceof Array);
let list: any[];
if (isArray) {
list = value;
} else {
list = [];
for (let key in value) {
list.push({
key: key,
value: value[key]
});
}
}
// 初始化数据
curList = list;
curIndex = 0;
lastNode = null;
for (let li = curList.length; curIndex < li; curIndex++) {
//渲染
// 拷贝一个target
let newNode: DisplayObject = context.target.clone(true, true);
// 添加到显示里
parent.addChild(newNode);
// 生成子域
let newScope: any = Object.create(forScope);
// 这里一定要用defineProperty将目标定义在当前节点上,否则会影响forScope
Object.defineProperty(newScope, "$index", {
configurable: true,
enumerable: false,
value: curIndex,
writable: false
});
// 如果是字典则额外注入一个$key
if (!isArray) {
Object.defineProperty(newScope, "$key", {
configurable: true,
enumerable: true,
value: curList[curIndex].key,
writable: false
});
}
// 注入上一个显示节点
Object.defineProperty(newScope, "$last", {
configurable: true,
enumerable: false,
value: lastNode,
writable: false
});
// 添加长度
Object.defineProperty(newScope, "$length", {
configurable: true,
enumerable: false,
value: curList.length,
writable: false
});
// 注入遍历名
Object.defineProperty(newScope, itemName, {
configurable: true,
enumerable: true,
value: (isArray ? curList[curIndex] : curList[curIndex].value),
writable: false
});
// 开始编译新节点
context.compiler.compile(newNode, newScope);
// 赋值上一个节点
lastNode = newNode;
}
});
// 返回节点
return context.target;
}
};
\ No newline at end of file
/**
* Created by rockyl on 2020-03-19.
*/
import {Compiler, IZri, ZriCommandData} from "./Interfaces";
import {Container, } from "../../../2d/display/index";
import {Command, commands, CommandContext} from "./ZriCommands";
import {cmdPrefix} from "../../utils/utils";
const interruptCmds = ['for', 'if'];
export class ZriCompiler implements Compiler {
private _root: Container;
private _entity: IZri;
constructor(root: Container) {
this._root = root;
}
get root(): Container {
return this._root;
}
init(entity: IZri): void {
this._entity = entity;
this.compile(this._root, entity.data);
}
compile(target: any, scope: any): void {
let cmdDatas = [];
let needInterrupt = false;
for (let key in target) {
if(key.indexOf(cmdPrefix) < 0){
continue;
}
let cmdData = this._entity.parseCommand(key, target[key]);
if (cmdData) {
cmdDatas.push(cmdData);
if(interruptCmds.indexOf(cmdData.cmdName) >= 0){
needInterrupt = true;
cmdDatas.splice(0, cmdDatas.length - 1);
break;
}
}
}
for (let cmdData of cmdDatas) {
delete target[cmdData.propName];
if (interruptCmds.indexOf(cmdData.cmdName) >= 0 && target['__originConfig']) {
delete target['__originConfig'].properties[cmdData.propName];
}
let cmd: Command = commands[cmdData.cmdName];
if (!cmd) {
cmdData.subCmd = cmdData.cmdName || "";
cmdData.cmdName = "prop";
cmd = commands[cmdData.cmdName];
}
cmd({
scope,
target,
entity: this._entity,
cmdData,
compiler: this,
})
}
if (!needInterrupt && target.children && target.children.length > 0) {
for (let child of target.children) {
this.compile(child, scope);
}
}
}
}
/** /**
* Created by rockyl on 2020-03-02. * Created by rockyl on 2020-03-02.
*/ */
import {Zri} from "./Zri";
import {Compiler, IZri, ZriOptions} from "./Interfaces";
import {ZriCompiler} from "./ZriCompiler";
import {Container} from "../../../2d/display/index";
import {safeEval} from "../../utils/utils";
/**
* 将数据模型和视图进行绑定
* @param store 数据
* @param view 视图
* @param options 一些额外参数
* @returns {IZri} 绑定实体对象
*/
export function bind(store: any, view: Container, options?: ZriOptions): IZri {
let compiler = new ZriCompiler(view);
return new Zri(store, compiler, options);
}
/**
* 通过配置生成数据
* @param exp
* @param computed
*/
export function createStore(exp, computed) {
let store = safeEval(exp) || {};
for (let item of computed) {
let getterCode = `return function(){
${item.script}
}`;
if (name && !store.hasOwnProperty(name)) {
Object.defineProperty(store, item.name, {
get: safeEval(getterCode),
})
}
}
return store;
}
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
import {Stage} from "../2d/display"; import {Stage} from "../2d/display";
import {registerCustomModuleFromConfig, registerScripts, RENDERER_TYPE, setProcessMetaLibs, StageScaleMode} from ".."; import {registerCustomModuleFromConfig, registerScripts, RENDERER_TYPE, setProcessMetaLibs, StageScaleMode} from "..";
import {GameStage} from "./game-warpper"; import {GameStage} from "./game-warpper/index";
import {setGlobalContext} from "./behavior-runtime"; import {setGlobalContext} from "./behavior-runtime";
import {globalLoader} from "../2d/loader/Loader"; import {globalLoader} from "../2d/loader/Loader";
import {Event} from "../2d/events/Event"; import {Event} from "../2d/events/Event";
......
...@@ -68,6 +68,22 @@ export function getDataByPath(scope, path, throwException?) { ...@@ -68,6 +68,22 @@ export function getDataByPath(scope, path, throwException?) {
} }
} }
/**
* 安全的eval方法
* @param code
* @param throwException
*/
export function safeEval(code, throwException = false){
let func = new Function(code);
try {
return func();
}catch (e) {
if (throwException) {
throw e;
}
}
}
/** /**
* 属性注入方法 * 属性注入方法
* @param target 目标对象 * @param target 目标对象
...@@ -303,6 +319,9 @@ export function instantiateScript(node, ScriptConfig) { ...@@ -303,6 +319,9 @@ export function instantiateScript(node, ScriptConfig) {
const script = node.scripts.add(scriptName, props, disabled); const script = node.scripts.add(scriptName, props, disabled);
} }
export const cmdPrefix = 'z-';
export const cmdOldPrefix = '//z-';
/** /**
* 属性注入 * 属性注入
* @param target * @param target
...@@ -310,7 +329,9 @@ export function instantiateScript(node, ScriptConfig) { ...@@ -310,7 +329,9 @@ export function instantiateScript(node, ScriptConfig) {
*/ */
export function injectProperties(target, source) { export function injectProperties(target, source) {
for (let key in source) { for (let key in source) {
propertyParse(key, target, source); if(!source.hasOwnProperty(cmdPrefix + key)){
propertyParse(key, target, source);
}
} }
return target; return target;
......
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Get Token Test</title>
</head>
<body>
<script src="getTokenKey"></script>>
<script src="//yun.duiba.com.cn/js-libs/px-token/0.0.1.4/px-token.min.js"></script>
<script>
function callApi(uri){
getPxToken(async function(e, t){
console.log(e, t);
let token = t;
let el = document.getElementById('token');
el.innerText = 'Token已获取:' + t;
try {
let resp = await fetch(uri + '?token=' + token);
let data = await resp.json();
console.log(data);
}catch (e) {
console.log(e);
}
});
}
</script>
<span id="token">Token获取中...</span>
<div>
<button onclick="callApi('join/tokenJoin.do')">请求[join/tokenJoin.do]</button>
<button onclick="callApi('join/join.do')">请求[join/join.do]</button>
</div>
</body>
</html>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment