ソースを参照

增加14章内容

增加14章内容
cwc1987 10 年 前
コミット
39ec305f3c

+ 5 - 0
SUMMARY.md

@@ -97,6 +97,11 @@
        * [管理动态创建的元素(Managing Dynamically Created Elements)](dynamic_qml/managing_dynamically_created_elements.md)
        * [管理动态创建的元素(Managing Dynamically Created Elements)](dynamic_qml/managing_dynamically_created_elements.md)
    * [跟踪动态对象(Tracking Dynamic Objects)](dynamic_qml/tracking_dynamic_objects.md)
    * [跟踪动态对象(Tracking Dynamic Objects)](dynamic_qml/tracking_dynamic_objects.md)
    * [总结(Summary)](dynamic_qml/summary.md)
    * [总结(Summary)](dynamic_qml/summary.md)
+* [JavaScript](javascript/README.md)
+   * [Browser/HTML vs QtQuick/QML](javascript/browserhtml_vs_qtquickqml.md)
+   * [JavaScript语法(The Language)](javascript/the_language.md)
+   * [JS对象(JS Objects)](javascript/js_objects.md)
+   * [创建JS控制台(Creating a JS Console)](javascript/creating_a_js_console.md)
 * [其它(Other)](other/README.md)
 * [其它(Other)](other/README.md)
    * [协作校正](other/collaboration_correction.md)
    * [协作校正](other/collaboration_correction.md)
 
 

+ 66 - 0
javascript/README.md

@@ -0,0 +1,66 @@
+# JavaScript
+
+JavaScript是web客户端开发的通用语言。基于node js它也开始引导web服务器的开发。因此它使非常适合在声明式QML语言上添加的命令性语言。QML本身作为一个申明式语言用于表达用户界面层次,但是这仅限于表达操作。有时你需要一个方法表达业务,使用JavaScript来完成。
+
+**注意**
+
+**在Qt社区有一个开放性的问题是在目前Qt程序中关于混合使用QML/JS/QtC++的正确性。通常建议的混合方式是在你的应用程序中将JS部分限制在最小,将你的业务逻辑部分放在QtC++中,UI逻辑放在QML/JS中。**
+
+**这本书趋向这种边界的划分,通常对于一个产品的开发这不一定是正确的混合方式,不是对于所有人都适用。最重要的是根据你的团队技能和个人品味而定。在接受推荐的时候保持你的怀疑。**
+
+下面有一个简短的例子是关于如何在QML中混合适用JS:
+
+```
+Button {
+  width: 200
+  height: 300
+  property bool toggle: false
+  text: "Click twice to exit"
+
+  // JS function
+  function doToggle() {
+    toggle = !toggle
+  }
+
+  onTriggered: {
+    // this is JavaScript
+    doToggle();
+    if(toggle) {
+      Qt.quit()
+    }
+  }
+}
+```
+
+因此在QML中JavaScript作为一个单独的JS函数,作为一个JS模块可以在很多地方使用,它可以与每一个右边的属性绑定。
+
+```
+import "util.js" as Util // import a pure JS module
+
+Button {
+  width: 200
+  height: width*2 // JS on the right side of property binding
+
+  // standalone function (not really useful)
+  function log(msg) {
+    console.log("Button> " + msg);
+  }
+
+  onTriggered: {
+    // this is JavaScript
+    log();
+    Qt.quit();
+  }
+}
+```
+
+在使用QML定义用户界面时,使用JavaScript完成功能。那么你需要写多少的JavaScript呢?这取决于你的风格和你对JS开发的熟悉程度。JS是一种松散型语言,这使得你很难发现类型缺陷。函数参数接受不同类型的变量值,会导致非常难发现严重的Bug。发现缺陷的方法是严格的单元测试或者验收测试。因此如果你在JS中开发真正的逻辑(不是粘贴代码)你应该使用测试优先的方法。通常使用这种混合开发非常成功的团队(Qt/C++与QML/JS),他们都会最小化前段逻辑中使用的JS,在后端Qt C++中完成更加复杂的工作。后端遵循严格的单元测试,这样前段的开发者可以信任这些代码并且专注于用户界面的需求。
+
+**注意**
+
+**通常:后端开发者由功能驱动,前段开发者由用户场景驱动。**
+
+
+
+
+

+ 8 - 0
javascript/browserhtml_vs_qtquickqml.md

@@ -0,0 +1,8 @@
+# Browser/HTML vs QtQuick/QML
+
+浏览器在运行时渲染HTML,执行HTML中相关的JavaScript。现今的web应用中相对于HTML包含了更多的JavaScript。浏览器中JavaScript运行在一些浏览器附加的标准ECMAScript环境。一个典型的浏览器中的JS环境知道访问浏览器窗口的窗口对象。也简单的基于JQuery的DOM选择器来提供CSS选择器。额外使用setTimeout函数在超时时调用函数。除了这些,JS存在于一个标准的JavaScript环境,类似于QML/JS。
+
+不同的是JS出现在HTML与QML中的方式。在HTML中,你只能在事件操作(event handlers),例如页面加载(page loaded),鼠标点击(mouse pressed)中添加JS。例如通常在页面加载中初始化你的JS,这在QML中与组件加载完成(Component.onCompleted)类似。例如你不能使用JS来绑定属性(至少不是直接绑定,AngularJS增强了DOM树允许这种操作,但这和典型HTML相去甚远)。
+
+所以在QML中JS是一种更加优秀的语言,并且与QML的渲染树高度集成。使得语言更具有可读性。除了这些,开发过HTML/JS应用程序的人会觉得在QML/JS中开发非常容易上手。
+

+ 142 - 0
javascript/creating_a_js_console.md

@@ -0,0 +1,142 @@
+# 创建JS控制台(Creating a JS Console)
+
+下面这个小的例子我们将创建一个JS控制台。我们需要一个输入区域允许用户输入表达式,和一个结果输出列表。由于这更像一个桌面应用程序,我们使用QtQuick控制模块。
+
+**注意**
+
+**在你下一个项目中包含一个JS控制台可以更好的用来测试。增加Quake-Terminal效果也有助于对你的客户留下更好的印象。为了更好的使用它,你需要评估JS控制台的控制范围,例如当前可见屏幕,核心数据模型,一个单例对象或者其它的东西。**
+
+![](http://qmlbook.github.io/_images/jsconsole.png)
+
+我们在Qt Creator中使用QtQuick controls创建一个Qt Quick UI项目。把这个项目取名为JSConsole。完成引导后,我们已经有了一个基础的应用程序框架,这个框架包含一个应用程序窗口和一个菜单。
+
+我们使用一个TextFiled来输入文本,使用一个Button来对输入求值。表达式求值结果使用一个机遇链表模型(ListModel)的链表视图(ListView)显示,每一个链表项使用两个标签显示表达式和求值结果。
+
+```
+// part of JSConsole.qml
+ApplicationWindow {
+  id: root
+
+  ...
+
+  ColumnLayout {
+      anchors.fill: parent
+      anchors.margins: 9
+      RowLayout {
+          Layout.fillWidth: true
+          TextField {
+              id: input
+              Layout.fillWidth: true
+              focus: true
+              onAccepted: {
+                  // call our evaluation function on root
+                  root.jsCall(input.text)
+              }
+          }
+          Button {
+              text: qsTr("Send")
+              onClicked: {
+                  // call our evaluation function on root
+                  root.jsCall(input.text)
+              }
+          }
+      }
+      Item {
+          Layout.fillWidth: true
+          Layout.fillHeight: true
+          Rectangle {
+              anchors.fill: parent
+              color: '#333'
+              border.color: Qt.darker(color)
+              opacity: 0.2
+              radius: 2
+          }
+
+          ScrollView {
+              id: scrollView
+              anchors.fill: parent
+              anchors.margins: 9
+              ListView {
+                  id: resultView
+                  model: ListModel {
+                      id: outputModel
+                  }
+                  delegate: ColumnLayout {
+                      width: ListView.view.width
+                      Label {
+                          Layout.fillWidth: true
+                          color: 'green'
+                          text: "> " + model.expression
+                      }
+                      Label {
+                          Layout.fillWidth: true
+                          color: 'blue'
+                          text: "" + model.result
+                      }
+                      Rectangle {
+                          height: 1
+                          Layout.fillWidth: true
+                          color: '#333'
+                          opacity: 0.2
+                      }
+                  }
+              }
+          }
+      }
+  }
+}
+```
+
+求值函数jsCall不会做求值操作,而是将它的内容移动到JS模块(jsconsole.js)完成清晰的分离。
+
+```
+// part of JSConsole.qml
+
+import "jsconsole.js" as Util
+
+...
+
+ApplicationWindow {
+  id: root
+
+  ...
+
+  function jsCall(exp) {
+      var data = Util.call(exp);
+      // insert the result at the beginning of the list
+      outputModel.insert(0, data)
+  }
+}
+```
+
+为了安全我们不在JS中调用eval函数,这可能导致用户修改局部作用域。我们使用constructor函数在运行时创建JS函数,并在我们的作用域中传入变量值。由于函数可能随时都在创建,它不能扮演关闭和存储它私有作用域的角色,我们需要使用 this.a = 10 来存储值10在这个函数的作用域。这个作用域由脚本设置到变量作用域。
+
+```
+// jsconsole.js
+.pragma library
+
+var scope = {
+  // our custom scope injected into our function evaluation
+}
+
+function call(msg) {
+    var exp = msg.toString();
+    console.log(exp)
+    var data = {
+        expression : msg
+    }
+    try {
+        var fun = new Function('return (' + exp + ');');
+        data.result = JSON.stringify(fun.call(scope), null, 2)
+        console.log('scope: ' + JSON.stringify(scope, null, 2) + 'result: ' + result)
+    } catch(e) {
+        console.log(e.toString())
+        data.error = e.toString();
+    }
+    return data;
+}
+```
+
+调用函数返回的数据是一个JS对象,包含了一个结果,表达式和错误属性:data: { expression: {}, result: {}, error: {} }。我们可以直接在链表模型(ListModel)中使用这个JS对象,并且可以通过代理(delegate)访问它,例如model.expression会得到输入的表达式。为了让例子更加简单,我们忽略了错误的结果。
+
+

+ 90 - 0
javascript/js_objects.md

@@ -0,0 +1,90 @@
+# JS对象(JS Objects)
+
+在使用JS工作时,有一些对象和方法会被频繁的使用。下面是它们的一个小的集合。
+
+* Math.floor(v),Math.ceil(v),Math.round(v) - 从浮点数获取最大,最小和随机整数
+* Math.random() - 创建一个在0到1之间的随机数
+* Object.keys(o) - 获取对象的索引值(包括QObject)
+* JSON.parse(s), JSON.stringify(o) - 转换在JS对象和JSON字符串
+* Number.toFixed(p) - 修正浮点数精度
+* Date - 日期时间操作
+
+你可以可以在这里找到它们的使用方法:JavaScript reference
+
+You can find them also at: [JavaScript reference](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference)
+
+下面有一些简单的例子演示了如何在QML中使用JS。会给你一些如何在QML中使用JS一些启发。
+
+**打印所有项的键(Print all keys from QML Item)**
+
+```
+Item {
+  id: root
+  Component.onCompleted: {
+    var keys = Object.keys(root);
+    for(var i=0; i<keys.length; i++) {
+      var key = keys[i];
+      // prints all properties, signals, functions from object
+      console.log(key + ' : ' + root[key]);
+    }
+  }
+}
+```
+
+**转换一个对象为JSON字符串并反转转换(Parse an object to a JSON string and back**)
+
+```
+Item {
+  property var obj: {
+    key: 'value'
+  }
+
+  Component.onCompleted: {
+    var data = JSON.stringify(obj);
+    console.log(data);
+    var obj = JSON.parse(data);
+    console.log(obj.key); // > 'value'
+  }
+}
+```
+
+**当前时间(Current Date)**
+
+```
+Item {
+  Timer {
+    id: timeUpdater
+    interval: 100
+    running: true
+    repeat: true
+    onTriggered: {
+      var d = new Date();
+      console.log(d.getSeconds());
+    }
+  }
+}
+```
+
+**使用名称调用函数(Call a function by name)**
+
+```
+Item {
+  id: root
+
+  function doIt() {
+    console.log("doIt()")
+  }
+
+  Component.onCompleted: {
+    // Call using function execution
+    root["doIt"]();
+    var fn = root["doIt"];
+    // Call using JS call method (could pass in a custom this object and arguments)
+    fn.call()
+  }
+}
+```
+
+
+
+

+ 79 - 0
javascript/the_language.md

@@ -0,0 +1,79 @@
+# JavaScript语法(The Language)
+
+这章不会对JavaScript作详细的介绍。有其它的书可以参考,请访问[Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript)
+
+JavaScript表面上是一种非常通用的语言,与许多其它语言没有什么不同:
+
+```
+function countDown() {
+  for(var i=0; i<10; i++) {
+    console.log('index: ' + i)
+  }
+}
+
+function countDown2() {
+  var i=10;
+  while( i>0 ) {
+    i--;
+  }
+}
+```
+
+但是注意JS有函数作用域,没有C++中的块作用域(查看[Functions and function scope](https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Functions_and_function_scope))。
+
+语句if ... else,break,continue也可以使用。switch相对于C++中只可以切换整数值,JavaScript可以切换其它类型的值:
+
+```
+function getAge(name) {
+  // switch over a string
+  switch(name) {
+  case "father":
+    return 58;
+  case "mother":
+    return 56;
+  }
+  return unknown;
+}
+```
+
+JS可以将几种值认为是false,如false,0,“”,undefined,null。例如一个函数范围默认值undefined。使用‘===’操作符验证是否为false。‘==’等于操作将会对类型转换做验证。如果条件允许,直接使用等于操作符‘===’可以更快更好的验证一致性(查看[Comparison operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators))。
+
+在JavaScript底层有它自己的实现方式,例如数组:
+
+```
+function doIt() {
+  var a = [] // empty arrays
+  a.push(10) // addend number on arrays
+  a.push("Monkey") // append string on arrays
+  console.log(a.length) // prints 2
+  a[0] // returns 10
+  a[1] // returns Monkey
+  a[2] // returns undefined
+  a[99] = "String" // a valid assignment
+  console.log(a.length) // prints 100
+  a[98] // contains the value undefined
+}
+```
+
+当然对比C++或者Java这种OO语言,JS的工作方式是不同的。JS不是一种纯粹的OO语言,它也可以称作基于原型语言。每个对象都有一个原型对象。对象是基于这个原型对象创建的。请阅读这本关于JavaScript的书了解更多[Javascript the Good Parts by Douglas Crockford ](http://javascript.crockford.com/)。
+
+可以使用在线JS控制台或者小片断的QML代码来测试小的JS片段代码:
+
+```
+import QtQuick 2.0
+
+Item {
+  function runJS() {
+    console.log("Your JS code goes here");
+  }
+  Component.onCompleted: {
+    runJS();
+  }
+}
+```
+
+
+
+
+
+