2016年2月

翠鸟冰谷位于延庆县最北部,是北京原始地貌独立发起的原始河谷,因谷内不时传来鸟鸣而得名。尤其此谷没有其它的户外团队涉足,所以其景色还没有破坏,谷内水量很大,但是水流缓慢,所以,相比于其它河谷来讲,其谷内冬天冰层更厚更硬,很适合冬天休闲踏冰。

本文最下面提供了本次踏冰全程记录视频,有兴趣的朋友可以看看。


一直对北方这种路这种景很有感觉,还遇到一队骑行的。

_DSC0163.jpg

_DSC0165.jpg

随拍

下面就是一些随拍记录的照片,有兴趣的慢慢看。

_DSC0174.jpg

_DSC0175.jpg

_DSC0184.jpg

_DSC0187.jpg

_DSC0178.jpg

_DSC0176.jpg

_DSC0255.1500.jpg

_DSC0373.1500.jpg

_DSC0382。1500.jpg

_DSC0192.1500.jpg

_DSC0202.1500.jpg

_DSC0203.1500.jpg

_DSC0207.1500.jpg

_DSC0217.1500.jpg

_DSC0218.1500.jpg

_DSC0220.1500.jpg

_DSC0222.1500.jpg

_DSC0224.1500.jpg

_DSC0225.1500.jpg

_DSC0226.1500.jpg

_DSC0244.1500.jpg

_DSC0245.1500.jpg

_DSC0253.1500.jpg

_DSC0256.1500.jpg

_DSC0257.1500.jpg

_DSC0268.1500.jpg

_DSC0275.1500.jpg

_DSC0282.1500.jpg

_DSC0289.1500.jpg

_DSC0300.1500.jpg

_DSC0311.1500.jpg

_DSC0315.1500.jpg

_DSC0318.1500.jpg

_DSC0320.1500.jpg

_DSC0336.1500.jpg

全程记录视频

本来是想着跟小泽同志去宜宜四元桥店拍拍人像的,但是正好赶上宜家做活动,全场 5 折,人太多,这是去宜家的路上,已经走不通了。

_DSC0008.jpg

宜家人像没拍成,一行四人转战去了南锣鼓巷,但是正好前一天晚上看到微信朋友圈里面某位朋友分享的文章里面提到了北锣,所以,下车后先往北锣鼓巷走一躺,已是夜里。

_DSC0018.jpg

巷子里面就如南锣一样,有很多小清新的类似下面这样的小店子,不同点在于,它们都不如南锣般热闹,但同样的,如果只是想着自己安静的瞎逛逛的话,北锣比南锣好得多。

_DSC0020.jpg

_DSC0021.jpg

它也不像南锣那般纯商业化,在巷子里面还有真正居住的人,他们还是过着像以前一样的老北京生活:

_DSC0029.jpg

巷内大多商店的店招与店名也都是有着小清新的特色,同时也不是很亮,整个巷子都比较暗。

_DSC0031.jpg

_DSC0027.jpg

_DSC0027.jpg

_DSC0043.jpg

有的小店门口还会提供几把椅子供路人休息:

_DSC0043.jpg

春节已过,元宵将至,门口都还贴着春联。

_DSC0077.jpg

与北锣相比,南锣鼓巷可谓人山人海了。

_DSC0089.jpg

_DSC0106.jpg

门店也更多,品种也更全:

_DSC0093.jpg

这种小商贩也多了起来:

_DSC0100.jpg

_DSC0144.jpg

接着也就没啥可逛的了,本来就是临时来这边走一下下,所以,快快的吃了个饭,就直接回家了。

_DSC0141.jpg

让我们通过本文从 0 开始使用 TypeScript 创建一个 Angular 2 应用。

先看看运行效果?

如果想先看看运行效果,可以点击访问我们在 Plunker 上面准备的示例,应用其实做的事情很简单,打开页面之后,开始加载程序代码,当程序代码加载完成之后,在页面中显示应用组件,该组件包含 My First Angular 2 App 字符。

其文件目录结构如下:

angular2-quickstart
|-app/
|-|-app.component.ts
|-|-main.ts 
|
|-index.html
|-license.md

功能文件包括一个 index.html 文件以及 app/ 目录下面的两个 TypeScript 文件。

当然了,我们开发不仅仅只是想在 Plunker 上面可以运行就可以了的,而是需要做一个真正的应用,包括:

  1. 配置我们的开发环境
  2. 创建 Angular 应用的根组件
  3. 启动它以让其接管整个页面
  4. 创建主页面 index.html

开发环境

我们首先需要一个地方存储整个应用的程序文件(应用项目目录),一些 TypeScript 配置以及一些开发与运行时需要的库。

创建新的项目目录

mkdir angular2-quickstart
cd angular2-quickstart

配置 TypeScript

我们必须要对 TypeScript 编译器进行一上结特殊的设置。

在项目目录下面添加一个名为 tsconfig.json 的文件,并复制/粘贴以下代码:

{
  "compilerOptions": {
    "target": "es5",
    "module": "system",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  },
  "exclude": [
    "node_modules",
    "typings/main",
    "typings/main.d.ts"
  ]
}

TypeScript Typings

许多 JavaScript 库对 JavaScript 的功能与语法进行了扩展,而这些扩展很多是 TypeScript 编译器本身不识别的,我们需要通过 TypeScript 类型定义文件 —— d.ts 教会编译器如何编译这些扩展,在项目目录下面新建一个名为 typings.json 的文件,编辑复制并粘贴下面的代码片段:

{
  "ambientDependencies": {
    "es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#6697d6f7dadbf5773cb40ecda35a76027e0783b2"
  }
}

添加项目必要的第三方库

我们推荐使用 npm 包管理工具管理第三方库。在项目目录中添加一个名为 package.json 的文件,复制并粘贴下面的代码片段:

{
  "name": "angular2-quickstart",
  "version": "1.0.0",
  "scripts": {
    "postinstall": "npm run typings install",
    "tsc": "tsc",
    "tsc:w": "tsc -w",
    "lite": "lite-server",
    "start": "concurrent \"npm run tsc:w\" \"npm run lite\" ",
    "typings" : "typings"
  },
  "license": "ISC",
  "dependencies": {
    "angular2": "2.0.0-beta.6",
    "systemjs": "0.19.20",
    "es6-promise": "^3.0.2",
    "es6-shim": "^0.33.3",
    "reflect-metadata": "0.1.2",
    "rxjs": "5.0.0-beta.0",
    "zone.js": "0.5.14"
  },
  "devDependencies": {
    "concurrently": "^1.0.0",
    "lite-server": "^2.0.1",
    "typescript": "^1.7.5",
    "typings":"^0.6.8"
  }
}

然后在项目目录中执行下面的命令以安装必要的第三方库:

npm install

第一个 Angular 组件

组件(Component) 是 Angular 最基本的概念,组件管理视图——用于显示网页内容或者对用户的反馈作出响应,技术上讲,一个组件就是一个类或者一个视频模板,我们在创建 Angular 应用的过程中,就是创建很多个组件的过程。

创建一个子目录

我们希望整个应用的代码都保存在项目根目录下名为 app/ 的子目录下,在终端中执行下面的命令即可:

mkdir app
cd app

创建组件文件

现在,添加一个名为 app.component.ts 的文件,复制并粘贴以下代码:

import { Component } from 'angular2/core';

@Component({
  selector: 'my-app',
  template: '<h1>我的第一个 Angular 2 应用</h1>'
})
export class AppComponent {

}

组件类(Component class)

在该文件的最下方,我们添加了一个空的,不做什么事情的名为 AppComponent 的类,当我们需要去做一个具有实质性功能的应用时,可以去扩展该类,但是在快速入门这个项目中,它不需要做任何事情。

模块

Angular 应用是模块化的,它们会使用很多个不同的模块去实现特定的功能,绝大多数应用的文件都会导出一个事物,比如一个组件,我们的 app.component 文件导出了 AppComponent 类。

export class AppComponent {

}

导出使得这个文件变成了一个模块,而这个文件的名称一般就是模块的名称,如上所述, app.component 就是我们的第一个模块。

表单是任何一个应用的基石,在 Angular 2 中,表单的实现作了不少改变。

曾经在 Angular 1 中,我们使用 ngModel 将表单数据映射至应用的数据模型,但是在 Angular 2,我们可以使用表单控件更加明确地构建表单,虽然看上去,相比于 Angular 1,我们需要写更多的代码,但是却不可以让我们不再需要去解决那些烦人的 ngModel 声明与数据绑定问题了。

一个简单的表单示例

<form [ngFormModel]="loginForm" (submit)="doLogin($event)">
  <input ngControl="email" type="email" placeholder="Email" />
  <input ngControl="password" type="password" placeholder="Password"| />
  <button type="submit">Log in</button>
</form>

与其相应的组件 JS 代码如下:

import {Component, FormBuilder, Validators} from 'angular2/angular2'

@Component({
  selector: 'login-page',
  templateUrl: 'login-page.html'
})
export class LoginPage {
  constructor (fb: FormBuilder) {
    this.loginForm = fb.group({
      email: ["", Validators.required],
      password: ["", Validators.required]
    });
  }

  doLogin(event) {
    console.log(this.loginForm.value);
    event.preventDefault();
  }
}

当我们运行该应用时,浏览器中会展示如下的登录表单

    +--------------------+
    | Email              |
    +--------------------+

    +--------------------+
    | Password           |
    +--------------------+

    +--------------------+
    |      Log in        |
    +--------------------+

表单构建器(FormBuilder)

在上面的示例中,我们使用了 FormBuilder,它可以让我们可以快速方便的定义表单控件以及每一个控件需要绑定的验证器,在上面示例中,我们创建了两个文本输入框 emailpassword

this.loginForm = fb.group({
  email: ["", Validators.required],
  password: ["", Validators.required]
})

控件组(ControlGroup)

FormBuilder 创建的就是 ControlGroup 实例,我们称之为 form,除了使用 FormBuilder 之外,我们还可以直接手工构建 ControlGroup

this.loginForm = new ControlGroup({
  email: new Control("email", Validators.required),
  password: new Control("password", Validators.required)
});

但是在实际的开发中,使用 FormBuilder 会方便很多。

表单指令 (For,m Directives)

上面的示例中,你应该已经注意到了,没有使用一个 ngModel 声明,但是我们使用 ngControl 将表单中的值映射至控件对象中。

<input ngControl="email" type="email" placeholder="Email" />

这将 email 输入框 ”绑定“ 至了 email 控件。

自定义验证器

我们可以创建自定义的验证器,它就是一个简单的函数:

function containsMagicWord(c: Control) {
  if(c.value.indexOf('magic' >= 0) {
    return {
      noMagic: true
    }
  }
  
  // Null 表示验证通过
  return null;
}

this.loginForm = fb.group({
  email: ["", containsMagicWord],
  password: ["", Validators.required],
});

处理表单数据

我们可以通过很方便的访问表单对应的 JavaScript 对象,或者某一个控件的值:

doLogin(event) {
  // 展示表单的数据
  var formData = this.loginForm.value;
 
  // 或者获取控件的值
  var email = this.loginForm.controls.email.value;

  event.preventDefault();
}

在 Angular 2 中,使用括号 () 绑定事件,并触发组件类中相应的方法,比如:

@component(...)
class MyComponent {
  clicked(event) {

  }
}

模板如下:

<button (click)="clicked()">点击我</button>

委托

Angular 2 采用普通 DOM 事件一样的机制处理事件,它们同样可以冒泡,我们不需要做什么特别的工作。

事件对象

要访问事件对象,只需要将 $event 作为事件出发的​参数即可。

@Component(...)
class MyComponent {
  clicked(event) {
    console.log(event(
  }
}

模板如下:

<button (click)="clicked($event)">点击我</button>

Angular 2 中的模板与 Angular 1 中的模板非常类似,但是还是有了很多的小改进。

简单示例

下面这个示例展示了一个 Angular 2 模板,它展示出我的姓名以及我喜欢的事物。

<div>
  您好,我叫 {{ name }} ,我喜欢 {{ thing }}。
</div>

{{}} :渲染

要渲染出某一个变量的值 ,我们可以使用双大括号 {{}}

我的名字叫 {{ name }}

在渲染声明中,我们还像 Angular 1 一样可以使用管道工具(Pipes`),比如过滤器,他们可以转换一个值为另一个值,或者将一段字符串本地话,或者可以将一个数字按照本地的货币数值格式化。

[] :绑定属性

要为一个组件绑定一个属性,可以使用 [] 声明,如果你在组件中有一个 this.currentVolume 声明,那么我们将可以将该值单向同步至组件,以帮助组件可以实时具有该属性的值:

<video-control [volume]="currentVolume"></video-control>

() :事件监听

要在一个组件上监听一个事件,可以使用 () 声明:

<my-component (click)="onClick($event)"></my-component>

[()] :数据双向绑定

要实现数据的双向绑定,我们可以使用 [()] 声明:

<input [(ngModel)]="myName" />

此时,this.myName 的值将与 input 的值双向同步。

* : 星号

* 声明表示该指令把当前组件作为一个模板,而且不会直接将其按愿你渲染,比如 ngFor 指令遍历出 items 中的每一个 item<my-component> 每一个 item 会创建一个组件的实例,但是组件本身的声明并不会被渲染出来。

<my-component *ngFor="#item fo items">
</my-component>

其它类似的指令还有 *ngIf*ngSwitch 等。

Angular 2 应用的生命周期需要经过一个多级的启动过程,我们可以在 App 启动、运行与创建/销毁组件的过程中响应大家的事件。

启动

Angular 2 应用需要通过应用的 根组件 (root component) 启动,在我们的主 JS 文件中,我们可以像下面这样写:

import {Component, bootstrap} from 'angular2/angular2'

// 注解部分
@Component({
  selector: 'my-app',
  template: '<h1>你好,{{ name }}</h1>'
})
// 组件控制器
class MyApp {
  constructor() {
    this.name = '潘韬'
  }
}

bootstrap(MyApp)

该代码片段中,你可以添加应用级别的代码与配置等,它的模板将是其它所有组件的容器。

组件初始化

当一个组件创建成功之后,它的构建函数 (constructor) 将被调用,在该函数中,你可以执行组件状态的初始化工作,但是如果应用依赖子组件的属性与数据的话,那么需要先等待子组件先完成初始化。要实现这样的功能,只需要使用生命周期事件 ngOnInit 即可,我们可以在 constructor 中使用 setTimeout 来模拟出相似的效果。

import {Component, bootstrap} from 'angular2/angular2'

@Component({
  selector: 'street-map',
  template: '<map-window></map-window><map-controls></map-controls>'
})
class StreetMap {
  constructor() {
    this.name = '潘韬'
  }

  setMapWindow(mapWindow) {
    this.mapWindow = mapWindow;
  }

  setMapControls(mapControls) {
    this.mapControls = mapControls;
  }

  ngOnInit() {
    // Properties are resolved and things like
    // this.mapWindow and this.mapControls
    // had a chance to resolve from the
    // two child components <map-window> and <map-controls>
  }
}

组件的生命周期

就像 ngOnInit 一样,我们可以在一个组件的生命周期中跟踪多个事件,下面列举出了部分常见的事件,查看完整的 Angular 2 生命周期事件钩子,可以查看官方文档

import {Component} from 'angular2/angular2'

@Component({
  selector: 'street-map',
  template: '<map-window></map-window><map-controls></map-controls>'
})
class StreetMap {
  constructor() {
    this.name = '潘韬';
  }

  ngOnInit() {

  }

  ngOnDestroy() {

  }

  ngOnCheck() {

  }

  ngOnChanges(changes) {

  }

  ngAfterContentInit() {

  }

  ngAfterContentChecked() {

  }

  ngAfterViewInit() {

  }

  ngAfterViewChecked() {

  }
}

在 Angular 2 中,组件(Component)是创建页面元素与实现业务逻辑的主要方式,与之相对应的,在 Angular 1 中,我们通过 directivecontrollersscope 等技术去实现,但是在 Angular 2 中,所有前面的这些实现都被 组件 取代。

一个最简单的 Angular 2 组件示例

下面的这个组件将展示出我的姓名,然后带有一个按钮,当按钮被点击时,将在浏览器的 console 中打印出我的名字。

import {Component} from 'angular2/angular2'

@Component({
  selector: 'my-component',
  template: '<div>大家好,我的名字叫 {{ name }},<button (click)="sayMyName()">叫一声我的名字</button>'
})
export class MyComponent({
  constructor() {
    this.name = '潘韬'
  }

  sayMyName() {
    console.log('我的名字叫', this.name)
  }
})

当我们在 HTML 模板中使用 `' 标签时,该组件将被创建。

Ionic V2 与 Ionic V1 一样提供了 CLI 工具与 GUI 的工具。

安装 Ionic V2

安装 Ionic 2,可以使用下面的命令:

npm install -g ionic@beta
完全不需要担心 Ionic V1 版本的项目,Ionic@Beta 可以完全兼容 Ionic V1 的项目。

安装完成之后可以使用下面的命令创建新项目:

ionic start cutePuppyPics --v2

运行新创建的项目, cd 进入项目目录之后,运行 ionic serve 命令即可:

cd cutePuppyPics
ionic serve

执行之后,即可像 Ionic v1 一样在浏览器中查看项目了。

构建

要构建 Ionic 项目,需要先安装 cordova

sudo npm install -g cordova

iOS 构建

ionic platform add ios
你需要先安装 XCodeXCode 允许你直接为 iOS 系统的目标设备构建应用。添加了 iOS 系统之后,即可使用下面的命令运行模拟器:
ionic emulate ios

Android 构建

ionic platform add android

接下来你还需要安装 Android SDK ,Android SDK 允许你为 Android 目录设备构建应用,虽然 Android SDK 本身就带了一个模拟器,但是更加推荐你使用 Genymotion

ionic run android

迁移

Ionic 1.x 是基于 Angular 1.x 技术的,同样的 Ionic 2.x 基于 Angular 2.x,所以,虽然 Ionic 本身的理念没有太多改变,但是代码的写法也因为 Angular 的改变而变得很不一样,Angular 2.x 使用了完全不一样的语法与代码结构(要了解 Angular 2.x 的变化,可以查看 学习 Angular 2 这个网站。

下面这个是 Ionic 1.x 中的写法:

.config(function($stateProvider) {
  $stateProvider
  .state('main', {
    url: '/',
    templateUrl: 'templates/main.html',
    controller: 'MainController'
  })
})

.controller('MainController', function() {

})

现在在 Ionic 2.x 中可以像下面这样写:

@Page({
  templateUrl: 'main/main.html'
})

export class MainCmp {
  constructor() {

  }
}

从 Angular 1.x 迁移

ControllerAs 语法是一个 Angular 1.x 提供的功能,它可以我们不需要使用 $scope 变量即可做到数据绑定,而是将数据直接绑定至 Controller 上,在 Angular 2.x 中,ControllerAs 的实现更加简单了,对比下面是 Angular 1.x 实现:

index.html

<ion-content ng-controller="MainController">
  <ion-item>
    {{ data.text }}
  </ion-item>
</ion-content>

app.js

.controller('MainController', function($scope) {
  $scope.data = {
    text: 'hello world'
  }
})

将上面的示例改成 ControllerAs 语法只需要改变很小的一点代码:

index.html

<ion-content ng-controller="MainController as main">
  <ion-item>
    {{ data.text }}
  </ion-item>
</ion-content>

app.js

.controller('MainController', function() {
  this.data = {
    text: 'Hello World'
  }
})

TypeScript

TypeScript 是一个提供了 ES6 类 与类型注释的 JavaScript 超集 ,这使得我们可以在 Ionic 项目中按照 ES6 的标准来写。

app.js

.controller('MainController', function() {
  this.data = {
    text: 'Hello World'
  }
})

app.ts

export class MainController {
  constructor() {
    this.data = {
      text: 'Hello World'
    }
  }
}

项目结构

在 Angular 1.x 中,最好的项目实践是将所有的 JavaScript 脚本都放在一起,模板文件也放在一起,但是他们两者却是分开的,比如下面这样:

|-www/
|
|--js/
|--|-app.js
|--|-HomeController.js
|--|-DetailController.js
|
|--templates/
|--|-Home.html
|--|-Detail.html
|
|-index.html

但是在 Angular 2.x 中,推荐像下面这样的:

|-www/
|
|--Home/
|--|-HomeController.js
|--|-Home.html
|
|--Detail/
|--|-DetailController.js
|--|-Detail.html
|
|-index.html
|-app.js

2016 年 1 月 1 日0 点,跟温新泽两个在后海扫街,遇到这位唱街的老者,声音沧桑,曲调断肠,任眼前人来人往,却无法看到些许光亮,生活如此艰辛,背后只有一堵墙,无法回头,再多苦楚,也要艰难前行。

_DSC3972.jpg

这是一篇关于湖南湘西地区农村丧葬习俗的文章,里面会带有很多与丧事相关的文字与图片,在您阅读前,请先确定您对这类题材没有不适。


我的家乡是一个湖南西部的小县城,辰溪县,外公去年去世,第一次过年没有听到他的声音,所以,无意间又开始想起他来,我写不出能表达我内心对他怀念的词语,就再一次一个人细细的看了一遍送他最后一程的所有照片,然后古迹群里鲁言老师问了我一些关于丧葬照片的问题,很细节,所以,就想着,要不我就写写家乡的丧葬习俗吧,也算是对家乡习俗的一些文字记载。

外公去世的时间是2015年12月12日的凌晨三点多,听外婆说走得很突然,虽然生前遭受太多病痛的折磨,但是走的时候并没有再受煎熬,躺在床上想要上厕所,然后走了几步就坐到地上,之后就再也没有醒来,听说应该是心肌梗塞,因为肿瘤手痛的问题,而让我们大家都忽略了他的这个病,也算是我们做后辈的不孝吧,尤其是我,不善表达我的情感,但是我却很后悔为什么没有见到最后一面,在还有机会的时候,只剩下生后的缅怀。

我是2015年12月16日回到家里,家乡现在是这样的景像:

_DSC3140.jpg

请道人

人去世之后,需要做的第一件事情就是请道人(佛教)给逝者开路,亡者在道人举办了开路仪式之后才可以进入阴界,才能来世投胎。

具体的作法是道人带领孝子去主管本姓的“土堂”招魂后再回到家中,整个过程孝子牵着一只母鸡(爬路鸡,,寓意就是这个鸡在人的前面开道(开路),回家之后,母鸡放生。

这里面的道人(佛教)本身并不一定就是一个佛教徒,这群人更加类似于家传事业一样,一代传一代,子承父业,他们同样结婚、生子,喝酒吃肉,但是却通晓法事之术,我们可以认为,道人就是管着一方丧事法事的人,他们有自己的地域,是不允许(也没有人会请他们)去别人的地域做法事的。

请人唱老人歌

在请完道人的同时,还需要请人唱老人歌陪唱到晚上十二点。

此老人歌中的老人意为“去世”,即人年老后去世,而非老年的老,该词在此处是一个动词,“老人”即“人去世”,“老人歌”即“为去世之人唱的歌曲”,一般会请两至三人,唱歌是为了把已故之人吵醒。

老人歌就是一些古时的戏剧(唱书),如红兰贵打酒、薛丁山征西等。

出殡前晚称为大葬夜,需要唱通宵,而且唱的内容也与其它夜的内容不太一样,这个在下面会详细描述。

做道场(法事)

做道场就是做法事,只是在我们那边的农村都叫作道场,它有一根桅杆道场、二根桅杆道场、三根桅杆道场之分,做道场是需要念经,如金刚经、地藏经等

桅杆是什么?

酒席

红白事都会有酒席,亲朋好友邻里乡亲都会来家里面吃酒席,也会收人情,因为外公家房子外面就是竹林,空地不是很大,所以外公的灵屋和酒席不在一起,满席是在大舅舅的老房子(现在也都没有人住了,都在县城买了房子了)家办的,掌厨的也都是乡亲,每个村子都有几个,能做出同村人都喜欢吃的饭菜来。

而在出殡前,道士一直需要超度,而在超度时,我们这些做后辈的都需要去跪拜,尤其是外公的儿子们(也就是我们舅舅们)。

转灯

我们每过一段时间就需要转灯,就是后辈们拿着一根竹棍和一支香,跟着道士绕着棺材转圈,每走几步就要磕头,转完一次之后,需要向死者敬酒,一杯酒敬三次,敬完之后需要倒地上,香插入棺材前的香炉里。