如果你想检测并响应一个对象上的变化,你可以使用可观察的对象。如果您想检测和响应一系列对象的变化,请使用`observableArray`。这在许多场景中非常有用,在这些场景中,您正在显示或编辑多个值,并且需要在添加和删除项目时重复显示和消失UI的各个部分。
示例:
```
var myObservableArray = ko.observableArray(); // Initially an empty array
myObservableArray.push('Some value'); // Adds the value and notifies observers
```
*****
关键点:ObservalArray跟踪数组中的对象,而不是这些对象的状态
简单地将一个对象放入observableArray并不能使该对象的所有属性本身都可见。当然,如果您愿意,您可以使这些属性可见,但这是一个独立的选择。`observableArray`只跟踪它持有的对象,并在添加或删除对象时通知侦听器。
*****
预填充可观察的数组
如果希望可观察数组不以空开头,而是包含一些初始项,请将这些项作为数组传递给构造函数。例如:
```
// This observable array initially contains three objects
var anotherObservableArray = ko.observableArray([
{ name: "Bungle", type: "Bear" },
{ name: "George", type: "Hippo" },
{ name: "Zippy", type: "Unknown" }
]);
```
从## observableArray读取信息
在幕后,observableArray实际上是一个值为数组的可观察对象(另外,observableArray添加了一些下面描述的附加功能)。因此,您可以通过将ObservalArray作为一个无参数的函数调用来获取底层JavaScript数组,就像其他任何可观察对象一样。然后您可以从底层数组中读取信息。例如:
```
alert('The length of the array is ' + myObservableArray().length);
alert('The first element is ' + myObservableArray()[0]);
```
从技术上讲,您可以使用任何本机JavaScript数组函数来操作底层数组,但通常有更好的替代方法。KO的`observableArray`有自己的等效功能,它们更有用,因为:
它们适用于所有目标浏览器。(例如,本机JavaScript indexOf函数在ie8或更早版本上不起作用,但KO的indexOf可以在任何地方使用。)
对于修改数组内容的函数,如`push`和`splice`,KO的方法会自动触发依赖项跟踪机制,以便将更改通知所有注册的侦听器,并且您的UI会自动更新,这意味着使用KO的方法(即ObservalArray.push)之间存在显著差异(…)和JavaScript本地数组方法(即`observeArray().push(…)`,因为后者不会向数组的订阅者发送其内容已更改的任何通知。
*****
**indexOf**
indexOf函数返回与参数相等的第一个数组项的索引。例如,myObservableArray.indexOf('Blah')将返回第一个数组项的从零开始的索引,该索引等于Blah,如果找不到匹配值,则返回值-1。
*****
**slice**
slice 函数是原生 JavaScript 切片函数的 observableArray 等价物(即,它返回从给定开始索引到给定结束索引的数组条目)。 调用 myObservableArray.slice(...) 相当于在底层数组上调用相同的方法(即 myObservableArray().slice(...))。
*****
以下所有这些函数都相当于在底层数组上运行原生 JavaScript 数组函数,然后通知侦听器有关更改:
push( value ) — 在数组末尾添加一个新项目。
pop() — 从数组中删除最后一个值并返回它。
unshift( value ) — 在数组的开头插入一个新项目。
shift() — 从数组中删除第一个值并返回它。
reverse() — 反转数组的顺序并返回 observableArray(不是底层数组)。
sort() — 对数组内容进行排序并返回 observableArray。默认排序是按字母顺序排列的,但您可以选择传递一个函数来控制数组的排序方式。请参阅下面排序的示例。
splice() — 从给定索引开始移除并返回给定数量的元素。例如, myObservableArray.splice(1, 3) 从索引位置 1 开始删除三个元素(即第 2、第 3 和第 4 个元素)并将它们作为数组返回。
*****
sorted和### reversed
`sorted()` — 返回数组的排序副本。 如果您想保留可观察数组的原始顺序但需要按特定顺序显示它,这比排序更可取。
默认排序是按字母顺序排列的,但您可以选择传递一个函数来控制数组的排序方式。 您的函数应该接受数组中的任意两个对象,如果第一个参数较小,则返回负值,正值表示第二个较小,或者为零以将它们视为相等。 例如,要按姓氏对“person”对象数组进行排序,您可以编写:
```
var mySortedArray = ko.pureComputed(function () {
return myObservableArray.sorted(function (left, right) {
return left.lastName === right.lastName ? 0
: left.lastName < right.lastName ? -1
: 1;
});
});
```
`reversed() `— 返回数组的反转后的副本。
*****
replace,remove和removeAll
observableArray 添加了一些默认在 JavaScript 数组中找不到的更有用的方法:
replace( oldItem, newItem ) — 用 newItem 替换与 oldItem 相等的第一个值。
remove( someItem ) — 删除所有等于 someItem 的值并将它们作为数组返回。
remove( function (item) { return item.age < 18; } ) — 删除所有年龄属性小于 18 的值,并将它们作为数组返回。
removeAll( ['Chad', 132, undefined] ) — 删除所有等于 'Chad'、123 或 undefined 的值,并将它们作为数组返回。
removeAll() — 删除所有值并将它们作为数组返回。
*****
确定属性是否为 observableArray
在某些情况下,以编程方式确定您是否正在处理 observableArray 很有用。 Knockout 提供了一个实用函数 `ko.isObservableArray` 来帮助解决这种情况。
*****
通常,一个 observableArray 会在它发生更改后立即通知其订阅者。 但是如果 observableArray 被重复更改或触发昂贵的更新,您可能会通过限制或延迟更改通知来获得更好的性能。 这是使用 rateLimit 扩展器完成的,如下所示:
```
// Ensure it notifies about changes no more than once per 50-millisecond period
myViewModel.myObservableArray.extend({ rateLimit: 50 });
```
跟踪数组更改
尽管您可以像任何其他 observable 一样订阅和访问 observableArray,但 Knockout 还提供了一种超快速方法来找出 observable 数组的变化情况(即,刚刚添加、删除或移动了哪些项目)。 您订阅数组更改如下:
```
obsArray.subscribe(fn, thisArg, "arrayChange");
```
订阅变更的主要优点:
在大多数情况下,性能是 O(1),即基本上没有性能影响,因为对于简单的操作,(推送、拼接等)Knockout 提供更改日志而不运行任何差异算法。 如果您在不使用典型的数组变异函数的情况下进行了任意更改,则 Knockout 仅依赖于算法。
更改日志只为您提供实际更改的项目。
以下是如何报告更改的示例:
```
var myArray = ko.observableArray(["Alpha", "Beta", "Gamma"]);
myArray.push("Delta");
// Changes: [{ index: 3, status: 'added', value: 'Delta' }]
// New value: ["Alpha", "Beta", "Gamma", "Delta"]
myArray.pop();
// Changes: [{ index: 3, status: 'deleted', value: 'Delta' }]
// New value: ["Alpha", "Beta", "Gamma"]
myArray.splice(1, 2, "Omega");
// Changes:
// [{ index: 1, status: 'deleted', value: 'Beta' },
// { index: 1, status: 'added', value: 'Omega' },
// { index: 2, status: 'deleted', value: 'Gamma' }]
// New value: ["Alpha", "Omega"]
myArray.reverse();
// Changes:
// [{ index: 0, moved: 1, status: 'deleted', value: 'Alpha' },
// { index: 1, moved: 0, status: 'added', value: 'Alpha' }]
// New value: ["Omega", "Alpha"]
```
如上所示,更改报告为添加和删除值的列表。 删除项的索引引用原始数组,添加项的索引引用新数组。
当项目被重新排序时,如上面的最后一个例子所示,您还将获得移动的信息。 您可以选择忽略移动的信息,并将其解释为删除的原始 Alpha 和添加到数组末尾的不同 Alpha。 或者,您可以认识到移动的信息告诉您,您可以将添加和删除的值视为仅更改位置的同一项目(通过匹配索引)。
observableArray 在构造时启用了数组跟踪,但您可以扩展任何其他订阅(即 ko.observable 和 ko.computed),如下所示:
```
trackable = ko.observable().extend({trackArrayChanges: true});
```
- Magento概述
- 第一章:路线图
- 概述
- 前端技能
- 后端技能
- 第二章:Linux环境
- 1.安装虚拟机VirtualBox
- 2.创建虚拟机
- 3.安装Ubuntu系统
- Linux文件系统概述
- Linux常用操作命令
- 第三章:Docker专题
- Docker概述
- 1.基础
- 2.镜像
- 3.容器
- 4.容器互联
- 5.dockerfile
- 6.docker-compose
- 7.docker安装nginx
- 8.docker安装mysql
- 9.docker安装redis
- 10.docker安装php
- 11.docker配置nginx-php-mysql
- 12.docker-compose构建lamp
- 13.附录
- 第四章:LAMP环境
- Docker构建LAMP开发环境
- 一键安装LNMP/LAMP
- 第五章:Magento安装
- Magento环境要求
- Docker安装Magento
- 填充网站首页、分类、商品等
- 第六章:Linux开发模式
- 编辑器vscode及插件
- 开发模式之SSH
- 开发模式之SFTP
- 开发模式之git
- 第七章:Magento架构
- 架构概述
- 文件目录结构
- 数据库表解析之EAV
- Magento命令行
- 第八章:模块结构解析
- 模块目录结构
- 配置文件之env.php
- 配置文件-routes.xml
- 配置文件之module.xml
- 配置文件之webapi.xml
- 配置的方式及加载顺序
- mvc之controller
- mvc之model
- mvc之block
- mvc之模板
- api概述
- 第九章:自定义模块
- 自定义模块概述
- 建立模块
- 注册模块
- 创建控制器
- 创建Block
- 创建模板
- Model-Collection-ResourceModel
- 添加后台菜单
- 第十章:重写(Override)
- 重写概述
- 布局文件详解
- 定位布局文件
- 重写Controller
- 重写Template
- 重写Block
- 重写Model
- 重写其它类
- 第十一章:小部件(Widget)
- 1.Widget概述
- 2.Widget在CMS页面的应用
- 3.自定义一个Widget
- 4.Widget添加到前台页面
- 第十二章:主题(Theme)
- 主题概述
- 1.创建新的主题
- 2.添加全局css文件
- 3.模板分离到主题
- 4.主题模板与javascript
- 5.magento封装的js写法
- 6.layout布局解析
- 7.创建移动端主题
- 第十三章:Template专题
- 模板的指定
- 自定义模板
- 模板重写的规则
- 第十四章:Javascript专题
- magento中的javascript
- requirejs语法
- js的调用和初始化
- js的重写和扩展
- javascript使用mixins
- 第十五章:Knockoutjs专题
- knockoutjs的应用
- knockout简介
- Observables
- Observable Arrays
- Computed Observables
- Bindings(绑定)
- Visible和hidden绑定
- Text绑定
- html绑定
- class和css绑定
- style绑定
- attr绑定
- 表单-click绑定
- 表单-submit绑定
- 表单-value值绑定
- 表单-textInput绑定
- 表单-checked绑定
- 表单-options绑定
- data-bind语法
- binding上下文
- 第十六章:Checkout专题
- 结算页面概述
- 添加新的结帐步骤
- 添加自定义支付方式
- 结算前添加自定义验证
- 添加自定义配送方式
- 添加自定义配送验证
- 为邮政编码添加掩码
- 为字段添加自定义模板
- 结账页面添加新的input
- 在地址表单中添加字段
- 添加自定义配送地址
- 结算页面其它字段修改
- 自定义运输方式列表
- 线下支付方式添加字段
- 第十七章:实战案例解析
- 从零开发一个模块
- 1.需求分析
- 2.数据表与数据填充
- 3.建立module
- 4.路由
- 5.控制器
- 6.创建Block
- 7.创建布局
- 8.建立模板
- 9.建立Model层
- 10.查询数据
- 11.完善模板
- 12.小结
- 定制我的订单页面
- 1.需求分析
- 2.新建模块
- 3.重写:布局文件
- 4.Block文件
- 5.模板文件
- 6.添加css文件
- 7.测试定制结果
- 添加系统配置模块
- 1.需求分析
- 2.后台实现
- 3.前台实现
- 第三方登录到magento
- 1.需求分析
- 2.登录页表单
- 3.建立module
- 4.建立控制器-后端登录逻辑
- 5.建立控制器-登录中间页
- 6.建立中间页的layout文件
- 7.建立block文件
- 8.建立登录中间页模板
- 9.第三方登录扩展
- 保留心愿单商品
- 1.需求分析
- 2.Plugin机制-拦截器
- 3.心愿单修改示例
- 创建订单流程及扩展
- 1.需求分析
- 2.创建订单流程追踪
- 3.重写
- 用户注册添加字段
- 1-需求分析
- 2-功能实现
- 第十八章:RestApi专题
- webapi概述
- 如何访问一个api
- swagger介绍
- 将services配置为webapi
- 配置api示例
- 设置自定义路由
- 第十九章:设计模式专题
- 设计模式概述
- 创建型模式
- 工厂方法
- 抽象工厂
- 生成器
- 原型
- 单例
- 结构型模式
- 适配器
- 桥接
- 组合
- 装饰
- 外观
- 享元
- 代理
- 行为模式
- 责任链
- 命令
- 迭代器
- 中介者
- 备忘录
- 观察者
- 状态
- 策略
- 模板方法
- 访问者
- 第二十章:性能最佳实践
- 本章概述
- 硬件推荐
- 软件推荐
- 架构参考
- 开发环境建议
- 配置最佳实践
- 部署流程
- 高级设置
- 附录1:常用代码及问题整理
- 权限报错问题
- Magento定时任务
- Magento开发基础篇一
- Magento开发基础篇二
- Magento之CRUD
- Magento中获取各种url的方法
- Redis存储Session和缓存
- 发送邮件配置
- 检测用户登录信息
- 获取env.php中配置的变量
- 模板中获取当前页面url
- 获取用户默认配送地址
- Magento系统问题整理
- 结算页面不能选择账单地址
- 我应该执行什么命令?
- 追代码打印sql
- 忘记后台密码怎么办?
- 附录2:多语言应用
- 多语言概述
- 日语翻译引擎
- 附录3:插件安装与GMO
- 安装插件的方法
- GMO支付插件
- 附录4:Elasticsearch搜索和分词
- ElasticSearcch配置与安装
- ES实现搜索日语分词