【译】FuseJS简介(上)

官网原文:https://www.fusetools.com/learn/fusejs

FuseJS简介

FuseJS 是一个用来给跨平台App写业务逻辑的JavaScript框架。

提示:目前FuseJS还不支持输出WebGL。

起步

FuseJS代码有两种用法,一是可以嵌入在UX标记文件里的<JavaScript>标签内,二是外链JavaScript文件,就像这样:

<JavaScript File="SomeCode.js" />

代码嵌入的例子:

<JavaScript>
    console.log("Hello, FuseJS!");
</JavaScript>

模块 Modules

FuseJS执行的是CommonJS模块化系统的规范,每个代码文件或嵌入的代码段都是一个模块。

如果想要模块内的东西为外部可见,需要使用module.exports构造器:

<JavaScript>
    module.exports = {
        exportedSymbol: "Hello, rest of the world!"
    };
</JavaScript>

模块内没有通过module.exports输出的定义数据,则在外部不能直接访问:

<JavaScript>
    var data = [1, 2, 3];
    var invisible = "I'm invisible";

    module.exports = {
        data: data
    };
</JavaScript>

有时对其它JavaScript模块和UX代码的调用需要隐藏执行细节,这就起作用了。

导入模块

每个代码文件或嵌入的代码块都是一个模块。在JavaScript标签内加上一个模块并赋予ux:Global属性,其它模块就可以通过require导入该模块,如下例所示:

<JavaScript File="parse-1.5.0.min.js" ux:Global="Parse" />

同一个项目内的其它模块想要导入上例模块时,代码如下:

var Parse = require("Parse").Parse;

备注:目前只通过JS文件路径的话,还不能直接引用该模块,我们正在解决,请耐心等待!

具体示例:TODO App with Parse backend example

设计与动力

FuseJS的关键设计目标是使代码短小、干净并且只专注于App的实用功能,而那些UX导向的功能,如Layout、数据呈现、动画和手势回馈都留给UX声明标记和原生UI组件去解决。

在Fuse中,JavaScript写业务逻辑而UX标记负责呈现,这么分开的做法有如下明显的益处:

  • 性能 - 所有对性能要求高的任务都交给原生代码和原生UI组件搞定
  • 简单 - 声明代码易写、易读、易理解,甚至对编程不胜了解的人也能做到(易学)
  • 少犯错 - 少的声明意味着出事儿的机率少
    • 可视化工具 - Fuse有inspectortimelines等“拖放即可”的工具用来编辑UX标记。

注意Fuse有非常多的声明API(就是设计好的UX标记)可以代替JavaScript代码能做的任务,比如可控制的动画效果。

很多其他JavaScript框架将命令式的UI代码、动画和高性能要求的任务统统混入JavaScript,因此有些FuseJS的新手开始的时候也试着在Fuse中这么做,技术上的确有可能,但我们并不鼓励这么做。我们推荐新手花些时间研究Fuse官网的示例,找找用新方式做事的感觉。

用"view"(UX标记)和"logic"(JavaScript)分开的方式净化代码,这么做可以大大减少代码量,且更容易维护,还可以让UX设计师与程序员有效的分工合作。

如果你需要写高性能要求的业务逻辑,我们推荐你用原生代码写,或者用Uno,而不要用Javascript。

Observables(观察量?)

Observables(还是不翻译了,Observable是Fuse中一种特别的变量,用来处理数据变化的。)

Observables是一个FuseJS应用中的关键成分,主要处理数据绑定、反应式(Reactive)编程和异步编程。

一个Observable代表了一个可被观察的值,在Fuse里,Observables主要用于在JavaScript代码与UX标记之间做数据绑定。

Observables可以保存一个单独的值,也可以是一个0或多个元素的值的列表。当Observable里的值发生变化,它的subscribers(订户)就会收到通知。

Observables支持反应式(Reactive)编程和异步编程,极大简化了数据驱动的UI编程。

如何导入

var Observable = require('FuseJS/Observable');

基础用法

要创建一个Observable,首先需要调用Observable函数,初始值可以是0到多个。

  • Observable(<initial values>) - 构造函数

示例:

var emptyObservable = Observable();
var isSomethingEnabled = Observable(true);

如果Observable的初始值为空,则其.value === undefined.length === 0

Observable的值

如果Observable只有一个值,我们可以用.value属性来getset这个值:

var someString = Observable('foobar');
Console.Log(someString.value); // prints 'foobar'
someString.value = 'barfoo'; // sets the value, notifies subscribers.

当用.value属性设定了一个值后,所有订户都会被通知。

Observable 值列表

如果使用Observable保存一个值列表(多个值),我们可以用.add(item).remove(item)方法来操控这些值。

下例是用.length属性查询列表里值的数量:

var friends = Observable('Jake', 'Jane', 'Joe');
Console.Log(friends.length); // prints 3

friends.add('Gina');
Console.Log(friends.length); // prints 4

Observable函数

当用一个函数作为唯一的参数来初始化一个Observable时,它的.value的值是评估该函数后计算生成的。

当函数估值时,所有反应式依赖(Reactive dependencies)都会用所有其它关联Observables的值自动生成。

示例:

var firstName = Observable('John');
var lastName = Observable('Doe');

var fullName = Observable(function() {
    return firstName.value + ' ' + lastName.value;
})

上例中,如果firstNamelastName发生变化,fullName就会随之自动更新。

对,就这么神奇。

成员 Members

值的操作符 Value operators

value

该属性可以取得或设置当前Observable的值。

.value属性实际上相当于getAt(0)replaceAt(0)的简写,通常是用于单一值的Observerable,虽然这不一定是必须的。

if (isSomethingEnabled.value) {
    doSomething();
}
isSomethingEnabled.value = false;

值列表的操作符 List operators

length

该属性返回Observable值的总数。

var fruits = Observable('Orange', 'Apple', 'Pear');
Console.Log(fruits.length); //output: 3
getAt(index)

该属性返回给定索引位置的值。

var seasons = Observable('Summer', 'Fall', 'Winter', 'Spring');
Console.Log(seasons.getAt(2)); //output: 'Winter'
add(value)

Observables的值列表里添加值。

var colors = Observable('Red', 'Green');
colors.add('Blue');
remove(value)

Observable的值列表里删除首个 remove给出的值。

var shapes = Observable('Round', 'Square', 'Rectangular');
shapes.remove('Rectangular');
tryRemove(value)

试着从Observable的值列表里删除首个tryRemove给出的值,如果成功,返回true, 否则,返回false

var shapes = Observable("Round", "Square", "Rectangular");
if(shapes.tryRemove("Rectangular")) {
    Console.Log("success");
}
removeAt(index)
removeAt(index)

删除给定索引位置的值。

var shapes = Observable('Round', 'Square', 'Rectangular');
shapes.removeAt(2);
removeWhere(func)

用一个函数遍历值列表里的值,删除满足条件(func返回true的)的所有的值。

var hotPlaces = Observable(
    {name: "Oslo", temperature: 30},
    {name: "New York", temperature: 24},
    {name: "California", temperature: 27},
    {name: "Sydney", temperature: 10}
).removeWhere(function(place){
    return place.temperature < 20;
}); //Removes Sydney from the list
forEach(func)

Observerable值列表里的每个值调用一遍给定的函数。

var numbers = Observable(10, 2, 50, 3);
numbers.forEach(function(number) {
    Console.Log(number + " is a nice number!");
});
replaceAt(index, value)

把给定索引位置的值替换为新值。

var ingredients = Observable('sugar', 'milk', 'potato');
ingredients.replaceAt(2, 'flour'); //Replaces 'potato' with 'flour'
replaceAll(array)

Observable里的所有值全部替换为给定数组里的值。

var colors = Observable("Red", "Green", "Blue");
colors.replaceAll(["Orange", "Cyan", "Pink"]);
clear()

清除Observable里所有的值。

var colors = Observable("Red", "Green");
colors.clear();
indexOf(value)

Observable里找到首个给定的值,返回其索引位置。

var seasons = Observable("Summer", "Fall", "Winter", "Spring");
var index = seasons.indexOf("Winter"); // 2
contains(value)

如果变量里存在给定的值,返回true

Observable seasons = Observable("Summer", "Fall", "Winter", "Spring");
var winterExists = seasons.contains("Winter"); // true
refreshAll(newValues, compareFunc, updateFunc, mapFunc)

一共四个参数,第一个newValues用于更新Observable里所有项,基于什么条件要看后面的函数,第二个compareFunc函数用于比较两个项是否相等,如果发现相等则应用第三个函数updateFunc, 将现有项替换为新值,最后一个mapFunc函数将新发现的项映射到新的对象中。

var items = Observable({
    {id: 1, text: "one" },
    {id: 2, text: "two" },
    {id: 3, text: "tres" },
})
var newItems = [
    {id: 3, text: "three" },
    {id: 4, text: "four" },
    {id: 5, text: "five" }
]
items.refreshAll(newItems, 
    //Compare on ID
    function(oldItem, newItem){
        return oldItem.id == newItem.id;
    },
    // Update text
    function(oldItem, newItem){
        oldItem.text.value = newItem.text;
    },
    // Map to object with an observable version of text
    function(newItem){
        return { id:newItem.id, Observable(newItem.text)
    }
);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,559评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,258评论 25 707
  • 介绍 RxJS是一个异步编程的库,同时它通过observable序列来实现基于事件的编程。它提供了一个核心的类型:...
    泓荥阅读 16,578评论 0 12
  • 本篇文章介主要绍RxJava中操作符是以函数作为基本单位,与响应式编程作为结合使用的,对什么是操作、操作符都有哪些...
    嘎啦果安卓兽阅读 2,825评论 0 10
  • 作者 谢恩铭,公众号「程序员联盟」(微信号:coderhub)。转载请注明出处。原文:http://www.jia...
    程序员联盟阅读 31,751评论 17 26