Angular 状态管理的演进
如果应用使用单个的控制器管理所有的状态,Angular 中的状态管理将从单个有机的单元开始。如果是一个单页应用,一个控制器还有意义吗?我们从冰河世纪挣脱出来,开始将视图、控制器,甚至指令和路由拆分为更小的独立的单位。这是巨大的改进,但是对于复杂的应用来说,管理复杂的状态仍然是一个问题。对于我们来说,在控制器,服务,路由,指令和偶尔的模板中包含散步的状态是很常见的。可变的状态本身不是邪恶的,但是共享的可变状态则是灾难的入场券。
正如像 Angular 这样的现代 Web 框架永远地改变了我们以 jQuer 为中心的应用开发方式,React 从根本上改变了我们在使用现代 Web 框架时处理状态管理的方式。Redux 是这种改变的前沿和核心,因为它引入了一种优雅地,但是非常简单的方式来管理应用程序状态。值得一提的是,Redux 不仅是一个库,更重要的是它是一种设计模式,完全与框架无关,更巧的是可以与 Angular 完美合作。
整个文章的灵感来自 Egghead.io – Getting Started with Redux series by Dan Abramov. 除了创始人的说明没有更好的途径学习 Redux。它完全免费并且改变了我的编程方式。
redux 的美妙之处在于它可以使用简单的句子表达出来,总之,在我 “啊” 的时候就可以总结三个要点。
单个的状态树
redux 的基础前提是应用的整个状态可以表示为单个的被称为 store 的 JavaScript 对象,或者 application store,它可以被特定的被称为 reducers 的函数操作。同样重要的是状态是不变的,应用中只有 reducers 可以改变它。如上图所示,store 是整个应用世界的中心.
状态的稳固和不变使得理解和预测应用的行为变得指数级的容易。
事件流向上
在 redux 中,用户的事件被捕获然后发布到 reducer 处理。在 Angular 1.x 中,经常见到的反模式用法就是带有大堆的管理本地逻辑的庞大的控制器。通过将处理逻辑转移到 reducer,组件的负担将会变得很轻微。在 angular 2 中,你经常看到除了捕获事件并通过 output 发射出去的哑的控制器。
如上图所示,你会看到两个事件流。一个事件从子组件发射到父组件,然后到达 reducer。第二个事件流发射到 service 来执行一个异步操作,然后结果再发射到 reducer 。所有的事件流最终都到达 reducer 。
状态流向下
事件流向上的时候,状态流从父组件流向子组件。Angular 2 通过定义 Input 是的从父组件向子组件传递状态变得很简单。这对 change detection 有着深刻的含义,我们将稍后介绍。
@ngrx/store
通过引入 Observable 和 async 管道,Angular 2 的状态管理变得非常简单。我的朋友 Rob Wormald 使用 RxJS 创建了被称为 @ngrx/store 的Redux 实现。 这给予我们组合了 redux 和 Observable 的强大力量,这是非常强大的技术栈。
示例应用
我们将创建一个简单的主-从页面的 REST 应用,它有一个列表,我们可以选择并编辑摸个项目,或者添加新项目。使用它来演示 @ngrx/store 进行异步操作,我们将使用 json-server 来提供 REST API,使用 Angular 2 的 http 服务进行访问。如果你希望一个更简单的版本,可以获取 simple-data-flow 分支来跳过 HTTP 调用部分。
获取代码,让我们开始吧。
Code
打好基础
我们将在本文中涉及很多方面,所以我们尽量提供详细的步骤。总是需要一个建立概念的阶段,在开始之前需要一些基础。在本节中,我们将创建一个基础的 Angular 应用,为我们在应用程序的上下文中讨论 redux 和 ngrx 创建一个基础空间。不需要太多的关注细节,我们将不止一次地重新回顾所有的内容,以便强化我们所涵盖的想法。
Reducers Take One
为了便于我们的主-从接口,我们需要管理一个项目的数组和当前选中的项目。我们将使用 @ngrx/store 提供的 store,存储状态。
管理应用的状态,我们需要创建我们 items 和 selectedItem 的 reducers. 典型的 reducer 是一个接收一个状态对象和操作的函数。我们的 ngrx reducer 有一点不同在于第二个参数是一个对象,带有一个操作类型的 type 属性和对应数据的 payload 属性。我们还可以提供一个默认值来保证顺畅地初始化。
复制代码
// The “items” reducer performs actions on our list of items
export const items = (state: any = [],{type,payload}) = {
switch (type) {
default:
return state;
}
};
复制代码
我们会创建处理特定操作的 reducer ,但是现在,我们仅仅使用 switch 的 default 来返回 state. 上面的代码片段和下面的仅仅区别在于一个用于 items ,一个用于 selectedItem。分别看它们便于查看底层的处理模式。
复制代码
// The “selectedItem” reducer handles the currently selected item
export const selectedItem = (state: any = null,payload}) = {
switch (type) {
default:
return state;
}
};
复制代码
创建一个应用存储的接口的确可以便于理解 reducers 是如何用于应用的。在我们的 AppStroe 接口中,可以看到,单个对象中有一个 items 集合和一个持有单个 Item 的 selectedItem 属性。
export interface AppStore {
items: Item[];
selectedItem: Item;
}
如果你需要额外的功能,存储可以扩展新的键值对来容纳更新的模型。
注入存储
现在我们定义了 reducers,我们需要将它们添加到应用存储中,然后注入应用。第一步是将 items,selectedItem 和 provideStore 导入应用。provideStore 提供给我们一个应用存储在应用的生命周期中使用。
我们通过调用 provideStore 来初始化我们的存储,传递我们的 items 和 selectedItem 的 reducers. 注意我们需要传递一个适配我们 AppStore 接口的对象。
然后我们通过定义它作为一个应用的依赖项来使得存储对于整个应用有效,在我们调用 bootstrap 初始化应用的时候我们完成它。
复制代码
import {bootstrap} from ‘angular2/platform/browser’;
import {App} from ‘./src/app’;
import {provideStore} from ‘@ngrx/store’;
import {ItemsService,items,selectedItem} from ‘./src/items’;
bootstrap(App,[
ItemsService,// The actions that consume our store
provideStore({items,selectedItem}) // The store that defines our app state
])
.catch(err = console.error(err));
复制代码
你可能还注意到了我们也导入并注入了 ItemsService ,我们下一步就定义它,它是我们新存储的主要消费者。
创建 Items 服务
我们第一个简单的迭代是从存储中拉取 items 集合。我们将 items 集合类型化为包含 item 数组的 Observable 对象。将数组包装为一个 Observable 对象的好处是一旦在应用中使用这个集合就会更清晰。我们也将会注入我们的存储,使用我们前面定义的强类型接口 AppStore 。
复制代码
@Injectable()
export class ItemsService {
items: ObservableArrayItem;
constructor(private store: StoreAppStore) {
this.items = store.select(‘items’); // Bind an observable of our items to “ItemsService”
}
}
复制代码
因为我们使用键-值存储,我们可以通过调用 store.select(‘items’) 来获取集合并赋予 this.items 。select 方法返回一个含有我们集合的 Observable 对象。
要点!创建一个服务来从存储中获取 items 数据的原因是我们将在访问远程 API 的时候引入异步操作。这层抽象使我们在处理任何 reducer 处理之前可以容纳一些潜在的复杂异步问题。
消费 Items
现在我们创建了 items 服务,items 集合也已经可用,我们要在 App 组件中使用它了。类似 items,我们将 items 定义为 ObservableArrayItem,我们将 selectedItem 也定义为含有单个 Item 的 Observable 对象。
复制代码
export class App {
items: ObservableArrayItem;
selectedItem: ObservableItem;
constructor(private itemsService: ItemsService,private store: StoreAppStore) {
this.items = itemsService.items; // Bind to the “items” observable on the “ItemsService”
this.selectedItem = store.select(‘selectedItem’); // Bind the “selectedItem” observable from the store
}
}
复制代码
我们从 ItemsService 获取 items 并赋予 this.items,对于 selectedItem,我们直接从我们的存储中调用 store.select(‘selectedItem’) 来获取,如果你记得,我们创建了 ItemsService 来抽象异步操作。管理 selectedItem 本质上是同步的,所以我没有同样创建 SelectedItemService 。这是我使用 ItemsService 处理 items ,但是直接使用存储来处理 selectedItem 的原因。你完全有理由自己创建一个服务来同样处理。
显示项目
Angular 2 设计成使用小的特定组件来聚合组件。我们的的应用有两个组件称为:ItemsList 和 ItemDetail 分别表示所有项目的列表和当前选中的项目。
复制代码
@Component({
selector: ‘my-app’,
providers: [],
template: HTML_TEMPLATE,
directives: [ItemList,ItemDetail],
changeDetection: ChangeDetectionStrategy.OnPush
})
复制代码
我的语法高亮器不够好,所以我将它分为两个部分,实践中,我建议保持你的组件足够细粒度便于使用内嵌模板,太大的模板意味着你的组件做得太多了。
在 my-app 模板中,我们使用 items-list 组件的属性绑定将本地的 items 集合传递给 items-list 的 items. 这类似 Angular 1 中的隔离作用域,我们创建带有 input 类型的 items 属性的子组件,然后,将父组件中的 items 集合的值绑定到这个属性。因为我们在使用 Observable,所以可以使用 asyn 管道来直接赋值而不用抽取具体的值。需要指出的是在 Angular 1 中,我们需要调用服务,当 Promise 完成之后,我们要获取值并赋予一个绑定到的属性。在 Angular 2 中,我们可以直接将异步对象应用在模板中。
div
items-list [items]=”items | async”/items-list
/div
div
item-detail [item]=”selectedItem | async”/item-detail
/div
使用同样的模式,我将 selectedItem 使用 item-detail 组件处理。现在我们已经构建了应用的基础,我们现在可以深入 redux 应用的三个主要特性了。
中心化状态
重申一下,redux 最重要的概念就是整个应用的状态中心化为单个的 JavaScript 对象树。在我看来,最大的改变是从我们以前的 Angualr 应用方式转换到现在的方式。我们通过一个获取原始状态和操作的 reducer 函数来管理状态,通过执行一系列基于 Action 的逻辑操作并返回新的状态对象。我们将创建子组件来显示 items 和 selectedItem ,并留意它们被主组件,单个状态树填充的事实。
我们的 reducer 需要的仅仅是改变应用状态,我们从 selectedItem 的 reducer 开始,因为它是两个中最简单的那个。当存储发布一个类型为 SELECT_ITEM 的操作事件后,将会命中 switch 中的第一个选择,然后返回 payload 作为新的状态。简单地说,我们告诉 recuder : “拿到新的项目并作为当前选中的项目”,同时,Action 是自定义的字符串使用全部大写,经常定义为应用中的常量。
复制代码
export const selectedItem = (state: any = null,payload}) = {
switch (type) {
case ‘SELECT_ITEM’:
return payload;
default:
return state;
}
};
复制代码
由于我们的状态对象是只读的。对于每个操作的响应都是一个新的对象,上一个对象则没有变化。在实现 redux 的时候在 reducer 中强制不变性是关键点,我们将逐步讨论每个操作和如何实现。
复制代码
export const items = (state: any = [],payload}) = {
switch (type) {
case ‘ADD_ITEMS’:
return payload;
case ‘CREATE_ITEM’:
return […state,payload];
case ‘UPDATE_ITEM’:
return state.map(item = {
return item.id === payload.id ? Object.assign({},item,payload) : item;
});
case ‘DELETE_ITEM’:
return state.filter(item = {
return item.id !== payload.id;
});
default:
return state;
}
};
复制代码
ADD_ITEMS 作为新的数组返回我们传递的内容
CREATE_ITEM 返回包含了新项目的全部项目
UPDATE_ITEM 返回新数组,通过映射使用 Object.assign 克隆一个新对象。
DELETE_ITEM 返回过滤掉希望删除项目的新数组。
通过中心化我们的状态到单个的状态树,将操作状态的代码分组到 reducer 中是的我们的应用易于理解。另外的好处是将 reducer 中的业务逻辑分离到纯粹的单元中,这使得测试应用变得容易。
状态下降
先预览数据流是如何连接的,我们看一下 ItemsService,看看如何在 items 的 reducer 中初始化一个操作。最终我们将会替换 loadItems 方法是用 HTTP 调用,但是现在,我们假定硬编码一些数据,使用它初始化数组。执行一个操作,我们调用 this.store.dispatch 并传递一个类型为 ADD_ITEMS 和初始化数据的 action 对象。
复制代码
@Injectable()
export class ItemsService {
items:Observable ArrayItem;
constructor(private store:StoreAppStore) {
this.items = store.select(‘items’);
}
loadItems() {
let initialItems:Item[] = [
// ITEM OBJECTS HERE
];
this.store.dispatch({type: ‘ADD_ITEMS’,payload: initialItems});
}
}
复制代码
有趣的是每当我们派发 ADD_ITEMS 事件,我们本地的 items 集合就会相应自动更新,因为它通过 observable 实现。因为我们在 App 组件中消费 items,它也同样自动更新。并且如果我们传递这个集合给 ItemsList 组件,它也同样更新子组件。
Redux 是非常棒的设计模式,它基于不变数据结构。加入了 Obserable 之后,你拥有了超级便利的方式通过绑定到 Observable 的流对象将状态下发到应用。http://www.ly.com/travels/270266.html
http://www.ly.com/travels/270244.html
http://www.ly.com/travels/270050.html
http://www.ly.com/travels/270123.html
http://www.ly.com/travels/269996.html
http://www.ly.com/travels/269997.html
http://www.ly.com/travels/270135.html
http://www.ly.com/travels/270316.html
http://www.ly.com/travels/270117.html
http://www.ly.com/travels/269928.html
http://www.ly.com/travels/270308.html
http://www.ly.com/travels/269897.html
http://www.ly.com/travels/270142.html
http://www.ly.com/travels/270018.html
http://www.ly.com/travels/270400.html
http://www.ly.com/travels/270394.html
http://www.ly.com/travels/270536.html
http://www.ly.com/travels/270491.html
http://www.ly.com/travels/270446.html
http://www.ly.com/travels/270154.html
http://www.ly.com/travels/270211.html
http://www.ly.com/travels/270565.html
http://www.ly.com/travels/270606.html
http://www.ly.com/travels/270599.html
http://www.ly.com/travels/270652.html
http://www.ly.com/travels/270447.html
http://www.ly.com/travels/270641.html
http://www.ly.com/travels/270695.html
http://www.ly.com/travels/270711.html
http://www.ly.com/travels/270530.html
http://www.ly.com/travels/270731.html
http://www.ly.com/travels/270269.html
http://www.ly.com/travels/270782.html
http://www.ly.com/travels/270802.html
http://www.ly.com/travels/270832.html
http://www.ly.com/travels/270589.html
http://www.ly.com/travels/270612.html
http://www.ly.com/travels/270682.html
http://www.ly.com/travels/270602.html
http://www.ly.com/travels/270713.html
http://www.ly.com/travels/270956.html
http://www.ly.com/travels/270561.html
http://www.ly.com/travels/270710.html
http://www.ly.com/travels/271030.html
http://www.ly.com/travels/270743.html
http://www.ly.com/travels/269916.html
http://www.ly.com/travels/271044.html
http://www.ly.com/travels/270587.html
http://www.ly.com/travels/270784.html
http://www.ly.com/travels/270773.html
http://www.ly.com/travels/270626.html
http://www.ly.com/travels/270838.html
http://www.ly.com/travels/271115.html
http://www.ly.com/travels/270987.html
http://www.ly.com/travels/271204.html
http://www.ly.com/travels/270667.html
http://www.ly.com/travels/271025.html
http://www.ly.com/travels/270936.html
http://www.ly.com/travels/270980.html
http://www.ly.com/travels/271253.html
http://www.ly.com/travels/270954.html
http://www.ly.com/travels/271287.html
http://www.ly.com/travels/271004.html
http://www.ly.com/travels/270895.html
http://www.ly.com/travels/271223.html
http://www.ly.com/travels/271219.html
http://www.ly.com/travels/271390.html
http://www.ly.com/travels/271394.html
http://www.ly.com/travels/271399.html
http://www.ly.com/travels/271095.html
http://www.ly.com/travels/271051.html
http://www.ly.com/travels/270849.html
http://www.ly.com/travels/271226.html
http://www.ly.com/travels/271277.html
http://www.ly.com/travels/271503.html
http://www.ly.com/travels/271401.html
http://www.ly.com/travels/271600.html
http://www.ly.com/travels/271230.html
http://www.ly.com/travels/271190.html
http://www.ly.com/travels/271228.html
http://www.ly.com/travels/271229.html
http://www.ly.com/travels/271419.html
http://www.ly.com/travels/271468.html
http://www.ly.com/travels/271164.html
http://www.ly.com/travels/271423.html
http://www.ly.com/travels/271411.html
http://www.ly.com/travels/271723.html
http://www.ly.com/travels/271814.html
http://www.ly.com/travels/271443.html
http://www.ly.com/travels/271510.html
http://www.ly.com/travels/271438.html
http://www.ly.com/travels/271517.html
http://www.ly.com/travels/271482.html
http://www.ly.com/travels/271484.html
http://www.ly.com/travels/271458.html
http://www.ly.com/travels/271509.html
http://www.ly.com/travels/271710.html
http://www.ly.com/travels/271693.html
http://www.ly.com/travels/271544.html
http://www.ly.com/travels/271679.html
http://www.ly.com/travels/271682.html
http://www.ly.com/travels/271664.html
http://www.ly.com/travels/271725.html
http://www.ly.com/travels/271831.html
http://www.ly.com/travels/271854.html
http://www.ly.com/travels/271756.html
http://www.ly.com/travels/272256.html
http://www.ly.com/travels/272024.html
http://www.ly.com/travels/271897.html
http://www.ly.com/travels/272042.html
http://www.ly.com/travels/272060.html
http://www.ly.com/travels/272007.html
http://www.ly.com/travels/271847.html
http://www.ly.com/travels/272110.html
http://www.ly.com/travels/272037.html
http://www.ly.com/travels/272072.html
http://www.ly.com/travels/272460.html
http://www.ly.com/travels/272415.html
http://www.ly.com/travels/272444.html
http://www.ly.com/travels/271947.html
http://www.ly.com/travels/272095.html
http://www.ly.com/travels/272158.html
http://www.ly.com/travels/272302.html
http://www.ly.com/travels/272089.html
http://www.ly.com/travels/272119.html
http://www.ly.com/travels/272474.html
http://www.ly.com/travels/272644.html
http://www.ly.com/travels/272174.html
http://www.ly.com/travels/272421.html
http://www.ly.com/travels/272270.html
http://www.ly.com/travels/272346.html
http://www.ly.com/travels/272176.html
http://www.ly.com/travels/272217.html
http://www.ly.com/travels/272395.html
http://www.ly.com/travels/272775.html
http://www.ly.com/travels/272348.html
http://www.ly.com/travels/272541.html
http://www.ly.com/travels/272345.html
http://www.ly.com/travels/272841.html
http://www.ly.com/travels/272506.html
http://www.ly.com/travels/272697.html
http://www.ly.com/travels/272700.html
http://www.ly.com/travels/272542.html
http://www.ly.com/travels/272553.html
http://www.ly.com/travels/272785.html
http://www.ly.com/travels/272896.html
http://www.ly.com/travels/272712.html
http://www.ly.com/travels/272602.html
http://www.ly.com/travels/272757.html
http://www.ly.com/travels/272754.html
http://www.ly.com/travels/272654.html
http://www.ly.com/travels/272805.html
http://www.ly.com/travels/272660.html
http://www.ly.com/travels/273141.html
http://www.ly.com/travels/272713.html
http://www.ly.com/travels/272722.html
http://www.ly.com/travels/273188.html
http://www.ly.com/travels/272853.html
http://www.ly.com/travels/272796.html
http://www.ly.com/travels/273096.html
http://www.ly.com/travels/273056.html
http://www.ly.com/travels/273260.html
http://www.ly.com/travels/272914.html
http://www.ly.com/travels/272933.html
http://www.ly.com/travels/273152.html
http://www.ly.com/travels/273079.html
http://www.ly.com/travels/272973.html
http://www.ly.com/travels/273044.html
http://www.ly.com/travels/273117.html
http://www.ly.com/travels/273449.html
http://www.ly.com/travels/273522.html
http://www.ly.com/travels/273212.html
http://www.ly.com/travels/273545.html
http://www.ly.com/travels/273573.html
http://www.ly.com/travels/273190.html
http://www.ly.com/travels/273574.html
http://www.ly.com/travels/273250.html
http://www.ly.com/travels/273203.html
http://www.ly.com/travels/273255.html
http://www.ly.com/travels/273162.html
http://www.ly.com/travels/273268.html
http://www.ly.com/travels/273313.html
http://www.ly.com/travels/273384.html
http://www.ly.com/travels/273303.html
http://www.ly.com/travels/273762.html
http://www.ly.com/travels/273297.html
http://www.ly.com/travels/273425.html
http://www.ly.com/travels/273523.html
http://www.ly.com/travels/273480.html
http://www.ly.com/travels/273444.html
http://www.ly.com/travels/273652.html
http://www.ly.com/travels/273436.html
http://www.ly.com/travels/273686.html
http://www.ly.com/travels/273702.html
http://www.ly.com/travels/273708.html
http://www.ly.com/travels/273798.html
http://www.ly.com/travels/273692.html
http://www.ly.com/travels/274151.html
http://www.ly.com/travels/273770.html
http://www.ly.com/travels/273681.html
http://www.ly.com/travels/273792.html
http://www.ly.com/travels/273817.html
http://www.ly.com/travels/273690.html
http://www.ly.com/travels/274145.html
http://www.ly.com/travels/273691.html
http://www.ly.com/travels/274191.html
http://www.ly.com/travels/274190.html
http://www.ly.com/travels/273849.html
http://www.ly.com/travels/273821.html
http://www.ly.com/travels/274302.html
http://www.ly.com/travels/274237.html
http://www.ly.com/travels/274243.html
http://www.ly.com/travels/274240.html
http://www.ly.com/travels/274273.html
http://www.ly.com/travels/274050.html
http://www.ly.com/travels/273835.html
http://www.ly.com/travels/274035.html
http://www.ly.com/travels/273826.html
http://www.ly.com/travels/274373.html
http://www.ly.com/travels/274078.html
http://www.ly.com/travels/274505.html
http://www.ly.com/travels/273924.html
http://www.ly.com/travels/274298.html
http://www.ly.com/travels/274320.html
http://www.ly.com/travels/274342.html
http://www.ly.com/travels/274286.html
http://www.ly.com/travels/273955.html
http://www.ly.com/travels/274277.html
http://www.ly.com/travels/274650.html
http://www.ly.com/travels/274609.html
http://www.ly.com/travels/274424.html
http://www.ly.com/travels/274305.html
http://www.ly.com/travels/274328.html
http://www.ly.com/travels/274515.html
http://www.ly.com/travels/274398.html
http://www.ly.com/travels/274368.html
http://www.ly.com/travels/274384.html
http://www.ly.com/travels/274300.html
http://www.ly.com/travels/274434.html
http://www.ly.com/travels/274377.html
http://www.ly.com/travels/274876.html
http://www.ly.com/travels/274507.html
http://www.ly.com/travels/274454.html
http://www.ly.com/travels/274686.html
http://www.ly.com/travels/274605.html
http://www.ly.com/travels/274713.html
http://www.ly.com/travels/274765.html
http://www.ly.com/travels/274597.html
http://www.ly.com/travels/274667.html
http://www.ly.com/travels/274740.html
http://www.ly.com/travels/274804.html
http://www.ly.com/travels/274779.html
http://www.ly.com/travels/274792.html
http://www.ly.com/travels/275190.html
http://www.ly.com/travels/274769.html
http://www.ly.com/travels/274910.html
http://www.ly.com/travels/275099.html
http://www.ly.com/travels/274946.html
http://www.ly.com/travels/275070.html
http://www.ly.com/travels/274959.html
http://www.ly.com/travels/274864.html
http://www.ly.com/travels/274944.html
http://www.ly.com/travels/275197.html
http://www.ly.com/travels/275069.html
http://www.ly.com/travels/275152.html
http://www.ly.com/travels/274916.html
http://www.ly.com/travels/275169.html
http://www.ly.com/travels/275101.html
http://www.ly.com/travels/275021.html
http://www.ly.com/travels/275122.html
http://www.ly.com/travels/275168.html
http://www.ly.com/travels/275155.html
http://www.ly.com/travels/275216.html
http://www.ly.com/travels/275328.html
http://www.ly.com/travels/275346.html
http://www.ly.com/travels/275391.html
http://www.ly.com/travels/275511.html
http://www.ly.com/travels/275384.html
http://www.ly.com/travels/275408.html
http://www.ly.com/travels/275389.html
http://www.ly.com/travels/275468.html
http://www.ly.com/travels/275518.html
http://www.ly.com/travels/275480.html
http://www.ly.com/travels/275592.html
http://www.ly.com/travels/275553.html
http://www.ly.com/travels/275610.html
http://www.ly.com/travels/275474.html
http://www.ly.com/travels/275487.html
http://www.ly.com/travels/275438.html
http://www.ly.com/travels/275440.html
http://www.ly.com/travels/275606.html
http://www.ly.com/travels/275476.html
http://www.ly.com/travels/275882.html
http://www.ly.com/travels/275817.html
http://www.ly.com/travels/276057.html
http://www.ly.com/travels/275695.html
http://www.ly.com/travels/275897.html
http://www.ly.com/travels/275787.html
http://www.ly.com/travels/275986.html
http://www.ly.com/travels/276072.html
http://www.ly.com/travels/276004.html
http://www.ly.com/travels/276040.html
http://www.ly.com/travels/276006.html
http://www.ly.com/travels/275969.html
http://www.ly.com/travels/275974.html
http://www.ly.com/travels/276020.html
http://www.ly.com/travels/276108.html
http://www.ly.com/travels/276009.html
http://www.ly.com/travels/276026.html
http://www.ly.com/travels/276021.html
http://www.ly.com/travels/275973.html
http://www.ly.com/travels/276013.html
http://www.ly.com/travels/276055.html
http://www.ly.com/travels/276490.html
http://www.ly.com/travels/276554.html
http://www.ly.com/travels/276109.html
http://www.ly.com/travels/276130.html
http://www.ly.com/travels/270664.html
http://www.ly.com/travels/270656.html
http://www.ly.com/travels/270380.html
http://www.ly.com/travels/270259.html
http://www.ly.com/travels/270604.html
http://www.ly.com/travels/270384.html
http://www.ly.com/travels/270379.html
http://www.ly.com/travels/270320.html
http://www.ly.com/travels/270637.html
http://www.ly.com/travels/270738.html
http://www.ly.com/travels/270672.html
http://www.ly.com/travels/270624.html
http://www.ly.com/travels/270659.html
http://www.ly.com/travels/270625.html
http://www.ly.com/travels/270843.html
http://www.ly.com/travels/270760.html
http://www.ly.com/travels/271106.html
http://www.ly.com/travels/270820.html
http://www.ly.com/travels/270721.html
http://www.ly.com/travels/271001.html
http://www.ly.com/travels/271101.html
http://www.ly.com/travels/270792.html
http://www.ly.com/travels/271041.html
http://www.ly.com/travels/270909.html
http://www.ly.com/travels/270852.html
http://www.ly.com/travels/271167.html
http://www.ly.com/travels/270810.html
http://www.ly.com/travels/270795.html
http://www.ly.com/travels/270945.html
http://www.ly.com/travels/271227.html
http://www.ly.com/travels/270739.html
http://www.ly.com/travels/271017.html
http://www.ly.com/travels/270793.html
http://www.ly.com/travels/270901.html
http://www.ly.com/travels/271274.html
http://www.ly.com/travels/271049.html
http://www.ly.com/travels/270972.html
http://www.ly.com/travels/271351.html
http://www.ly.com/travels/271352.html
http://www.ly.com/travels/271350.html
http://www.ly.com/travels/271187.html
http://www.ly.com/travels/271140.html
http://www.ly.com/travels/271205.html
http://www.ly.com/travels/271307.html
http://www.ly.com/travels/271246.html
http://www.ly.com/travels/271311.html
http://www.ly.com/travels/271405.html
http://www.ly.com/travels/271402.html
http://www.ly.com/travels/271391.html
http://www.ly.com/travels/271379.html
http://www.ly.com/travels/271382.html
http://www.ly.com/travels/271414.html
http://www.ly.com/travels/271312.html
http://www.ly.com/travels/271238.html
http://www.ly.com/travels/271231.html
http://www.ly.com/travels/271488.html
http://www.ly.com/travels/271418.html
http://www.ly.com/travels/271430.html
http://www.ly.com/travels/271578.html
http://www.ly.com/travels/271779.html
http://www.ly.com/travels/271531.html
http://www.ly.com/travels/271559.html
http://www.ly.com/travels/271475.html
http://www.ly.com/travels/271877.html
http://www.ly.com/travels/271448.html
http://www.ly.com/travels/271446.html
http://www.ly.com/travels/271632.html
http://www.ly.com/travels/271657.html
http://www.ly.com/travels/271707.html
http://www.ly.com/travels/271721.html
http://www.ly.com/travels/271781.html
http://www.ly.com/travels/271449.html
http://www.ly.com/travels/271958.html
http://www.ly.com/travels/271771.html
http://www.ly.com/travels/272053.html
http://www.ly.com/travels/271792.html
http://www.ly.com/travels/272027.html
http://www.ly.com/travels/272054.html
http://www.ly.com/travels/271833.html
http://www.ly.com/travels/272142.html
http://www.ly.com/travels/271615.html
http://www.ly.com/travels/271801.html
http://www.ly.com/travels/271828.html
http://www.ly.com/travels/271972.html
http://www.ly.com/travels/272203.html
http://www.ly.com/travels/272249.html
http://www.ly.com/travels/272267.html
http://www.ly.com/travels/272312.html
http://www.ly.com/travels/271965.html
http://www.ly.com/travels/272059.html
http://www.ly.com/travels/272369.html
http://www.ly.com/travels/271865.html
http://www.ly.com/travels/272378.html
http://www.ly.com/travels/272064.html
http://www.ly.com/travels/271842.html
http://www.ly.com/travels/271940.html
http://www.ly.com/travels/272145.html
http://www.ly.com/travels/272464.html
http://www.ly.com/travels/272472.html
http://www.ly.com/travels/272121.html
http://www.ly.com/travels/272134.html
http://www.ly.com/travels/272120.html
http://www.ly.com/travels/272133.html
http://www.ly.com/travels/272126.html
http://www.ly.com/travels/272124.html
http://www.ly.com/travels/272320.html
http://www.ly.com/travels/272251.html
http://www.ly.com/travels/272123.html
http://www.ly.com/travels/272323.html
http://www.ly.com/travels/272461.html
http://www.ly.com/travels/272717.html
http://www.ly.com/travels/272469.html
http://www.ly.com/travels/272404.html
http://www.ly.com/travels/272499.html
http://www.ly.com/travels/272569.html
http://www.ly.com/travels/272783.html
http://www.ly.com/travels/272862.html
http://www.ly.com/travels/272377.html
http://www.ly.com/travels/272601.html
http://www.ly.com/travels/272450.html
http://www.ly.com/travels/272620.html
http://www.ly.com/travels/272536.html
http://www.ly.com/travels/272476.html
http://www.ly.com/travels/272571.html
http://www.ly.com/travels/272674.html
http://www.ly.com/travels/272984.html
http://www.ly.com/travels/272990.html
http://www.ly.com/travels/272720.html
http://www.ly.com/travels/272594.html
http://www.ly.com/travels/273084.html
http://www.ly.com/travels/272596.html
http://www.ly.com/travels/272619.html
http://www.ly.com/travels/272714.html
http://www.ly.com/travels/273115.html
http://www.ly.com/travels/272743.html
http://www.ly.com/travels/272937.html
http://www.ly.com/travels/272725.html
http://www.ly.com/travels/272909.html
http://www.ly.com/travels/272767.html
http://www.ly.com/travels/272772.html
http://www.ly.com/travels/273229.html
http://www.ly.com/travels/273287.html
http://www.ly.com/travels/272889.html
http://www.ly.com/travels/273116.html
http://www.ly.com/travels/273147.html
http://www.ly.com/travels/273028.html
http://www.ly.com/travels/273019.html
http://www.ly.com/travels/272935.html
http://www.ly.com/travels/273199.html
http://www.ly.com/travels/273453.html
http://www.ly.com/travels/273101.html
http://www.ly.com/travels/273309.html
http://www.ly.com/travels/273133.html
http://www.ly.com/travels/273070.html
http://www.ly.com/travels/273087.html
http://www.ly.com/travels/273547.html
http://www.ly.com/travels/273570.html
http://www.ly.com/travels/273538.html
http://www.ly.com/travels/273288.html
http://www.ly.com/travels/273157.html
http://www.ly.com/travels/273175.html
http://www.ly.com/travels/273343.html
http://www.ly.com/travels/273194.html
http://www.ly.com/travels/273225.html
http://www.ly.com/travels/273245.html
http://www.ly.com/travels/273253.html
http://www.ly.com/travels/273347.html
http://www.ly.com/travels/273392.html
http://www.ly.com/travels/273641.html
http://www.ly.com/travels/273478.html
http://www.ly.com/travels/273489.html
http://www.ly.com/travels/273648.html
http://www.ly.com/travels/273427.html
http://www.ly.com/travels/273947.html
http://www.ly.com/travels/273658.html
http://www.ly.com/travels/273987.html
http://www.ly.com/travels/273605.html
http://www.ly.com/travels/273680.html
http://www.ly.com/travels/273536.html
http://www.ly.com/travels/273661.html
http://www.ly.com/travels/273765.html
http://www.ly.com/travels/273727.html
http://www.ly.com/travels/273799.html
http://www.ly.com/travels/273725.html
http://www.ly.com/travels/273789.html
http://www.ly.com/travels/273777.html
http://www.ly.com/travels/273860.html
http://www.ly.com/travels/273791.html
http://www.ly.com/travels/273776.html
http://www.ly.com/travels/274257.html
http://www.ly.com/travels/274266.html
http://www.ly.com/travels/274282.html
http://www.ly.com/travels/273961.html
http://www.ly.com/travels/273914.html
http://www.ly.com/travels/274347.html
http://www.ly.com/travels/274033.html
http://www.ly.com/travels/274133.html
http://www.ly.com/travels/274092.html
http://www.ly.com/travels/274003.html
http://www.ly.com/travels/274233.html
http://www.ly.com/travels/274100.html
http://www.ly.com/travels/274371.html
http://www.ly.com/travels/274337.html
http://www.ly.com/travels/274144.html
http://www.ly.com/travels/274199.html
http://www.ly.com/travels/274167.html
http://www.ly.com/travels/274136.html
http://www.ly.com/travels/274259.html
http://www.ly.com/travels/274397.html
http://www.ly.com/travels/274528.html
http://www.ly.com/travels/274108.html
http://www.ly.com/travels/274761.html
http://www.ly.com/travels/274723.html
http://www.ly.com/travels/274426.html
http://www.ly.com/travels/274444.html
http://www.ly.com/travels/274375.html
http://www.ly.com/travels/274526.html
http://www.ly.com/travels/274446.html
http://www.ly.com/travels/274258.html
http://www.ly.com/travels/274463.html
http://www.ly.com/travels/274861.html
http://www.ly.com/travels/274538.html
http://www.ly.com/travels/274904.html
http://www.ly.com/travels/274897.html
http://www.ly.com/travels/274521.html
http://www.ly.com/travels/274545.html
http://www.ly.com/travels/274540.html
http://www.ly.com/travels/275020.html
http://www.ly.com/travels/274985.html
http://www.ly.com/travels/274726.html
http://www.ly.com/travels/274883.html
http://www.ly.com/travels/274641.html
http://www.ly.com/travels/274673.html
http://www.ly.com/travels/275128.html
http://www.ly.com/travels/274677.html
http://www.ly.com/travels/274790.html
http://www.ly.com/travels/274809.html
http://www.ly.com/travels/274714.html
http://www.ly.com/travels/275011.html
http://www.ly.com/travels/275236.html
http://www.ly.com/travels/274785.html
http://www.ly.com/travels/274801.html
http://www.ly.com/travels/274923.html
http://www.ly.com/travels/274862.html
http://www.ly.com/travels/274895.html
http://www.ly.com/travels/275227.html
http://www.ly.com/travels/275080.html
http://www.ly.com/travels/274999.html
http://www.ly.com/travels/275427.html
http://www.ly.com/travels/275063.html
http://www.ly.com/travels/275183.html
http://www.ly.com/travels/275065.html
http://www.ly.com/travels/275185.html
http://www.ly.com/travels/275547.html
http://www.ly.com/travels/275095.html
http://www.ly.com/travels/275113.html
http://www.ly.com/travels/275353.html
http://www.ly.com/travels/275369.html
http://www.ly.com/travels/275663.html
http://www.ly.com/travels/275253.html
http://www.ly.com/travels/275382.html
http://www.ly.com/travels/275299.html
http://www.ly.com/travels/275309.html
http://www.ly.com/travels/275283.html
http://www.ly.com/travels/275337.html
http://www.ly.com/travels/275342.html
http://www.ly.com/travels/275524.html
http://www.ly.com/travels/275820.html
http://www.ly.com/travels/275471.html
http://www.ly.com/travels/275481.html
http://www.ly.com/travels/275434.html
http://www.ly.com/travels/275503.html
http://www.ly.com/travels/275439.html
http://www.ly.com/travels/275630.html
http://www.ly.com/travels/276016.html
http://www.ly.com/travels/275818.html
http://www.ly.com/travels/275683.html
http://www.ly.com/travels/275646.html
http://www.ly.com/travels/275815.html
http://www.ly.com/travels/275738.html
http://www.ly.com/travels/275724.html
http://www.ly.com/travels/275816.html
http://www.ly.com/travels/276080.html
http://www.ly.com/travels/275656.html
http://www.ly.com/travels/275870.html
http://www.ly.com/travels/275857.html
http://www.ly.com/travels/275852.html
http://www.ly.com/travels/275867.html
http://www.ly.com/travels/275848.html
http://www.ly.com/travels/276229.html
http://www.ly.com/travels/275828.html
http://www.ly.com/travels/275967.html
http://www.ly.com/travels/276312.html
http://www.ly.com/travels/276114.html
http://www.ly.com/travels/276316.html
http://www.ly.com/travels/275988.html
http://www.ly.com/travels/276018.html
http://www.ly.com/travels/276122.html
http://www.ly.com/travels/276099.html
http://www.ly.com/travels/276117.html
http://www.ly.com/travels/276061.html
http://www.ly.com/travels/276126.html
http://www.ly.com/travels/276036.html
http://www.ly.com/travels/276107.html
http://www.ly.com/travels/276128.html
http://www.ly.com/travels/276286.html
http://www.ly.com/travels/276144.html
http://www.ly.com/travels/276189.html
http://www.ly.com/travels/276353.html
http://www.ly.com/travels/276295.html
http://www.ly.com/travels/276420.html
http://www.ly.com/travels/276417.html
http://www.ly.com/travels/276403.html
http://www.ly.com/travels/276440.html