angular4 (4)组件间通讯

<1>输入属性

定义:组件的输入属性,是指被@input装饰器注解的属性,用来从父组件接收数据

实例
1.新建order子组件

ng g component order

2.修改子组件控制器order.component.ts

/* 2.引入Input */
import { Component, OnInit,Input } from '@angular/core';

@Component({
  selector: 'app-order',
  templateUrl: './order.component.html',
  styleUrls: ['./order.component.css']
})
export class OrderComponent implements OnInit {
    /* 1.定义属性,用@Input装饰器注入 */
    @Input()
    stockCode:string;
    @Input()
    amount:number;

  constructor() { }
  ngOnInit() {
  }
}

3.修改子组件模版order.component.html

<!-- 3.修改模版 -->
<div>我是子组件</div>
<div>
    买{{amount}}只{{stockCode}}股票
</div>

4.修改父组件控制器app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
/* 4.定义父组件stock */
  stock = "";
}

5.修改父组件模版

<!-- 5.修改父组件模版 -->
<div>我是父组件</div>
<div>
  <!-- 双向绑定ngModel,在这个input上输入值的时候会改变stock的值 -->
  <input type="text" placeholder="请输入股票代码" [(ngModel)]="stock">
  <!-- 子组件里的stockCode属性的值为父组件的stock传入的 -->
  <app-order [stockCode]="stock" [amount]="100"></app-order>
</div>

若报错:Can't bind to 'ngModel' since it isn't a known property of 'input'
解决方式:修改app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { OrderComponent } from './order/order.component';

/* 重要:导入FormsModule */
import { FormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    AppComponent,
    OrderComponent,
  ],
  imports: [
    BrowserModule,
    FormsModule//2.此处添加FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

6.结果


18.jpg

<2>输出属性

实例
step1:
1.新建一个price子组件

ng g component price

2.修改price.component.ts

import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'app-price',
  templateUrl: './price.component.html',
  styleUrls: ['./price.component.css']
})
export class PriceComponent implements OnInit {
//2.定义两个对象,代码和价格
stockCode:string = "IBM";
price:number;
  constructor(){
    setInterval(()=>{
        /* 3.new一个Price对象 */
        let pr:Price = new Price(this.stockCode,100*Math.random());
        /* 4.将获取到的最后一次的价格赋值给price */
        this.price = pr.lastPrice;
    },1000)
   }
  ngOnInit() {
  }
}
/* 1.定义一个报价对象 */
export class Price {
    constructor(public stockCode:string,
                public lastPrice:number
    ){}
}

2.修改price.component.html模版

<div>
    这里是报价组件
</div>
<div>
    //用了number管道进行数据处理
    股票代码是{{stockCode}},股票价格是{{price | number:'2.2-2'}}
</div>

3.结果

19.jpg

其中价格每隔一秒变化一次
step2:
将价格属性输出,让外部组件可以订阅,即在子组件中将信息发射出来,然后在父组件中接收到这个信息
4.修改price.component.ts文件

import { Component, OnInit,EventEmitter,Output } from '@angular/core';

@Component({
  selector: 'app-price',
  templateUrl: './price.component.html',
  styleUrls: ['./price.component.css']
})
export class PriceComponent implements OnInit {
stockCode:string = "IBM";
price:number;
//1.EventEmitter对象可以发射和订阅事件
@Output()
lastPrice:EventEmitter<Price> = new EventEmitter();
  constructor(){
    setInterval(()=>{
        let pr:Price = new Price(this.stockCode,100*Math.random());
        this.price = pr.lastPrice;
      //2.用emit方法往外发射事件,其中发射的变量是泛型Price指定的,在这里即是pr
      this.lastPrice.emit(pr);
    },1000)
   }

  ngOnInit() {
  }

}
export class Price {
    constructor(public stockCode:string,
                public lastPrice:number
    ){}
}

5.修改app.component.ts--父组件

import { Component } from '@angular/core';
import {Price} from "./price/price.component"


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  stock = "";
  //1.声明一个Price类型的属性,因为子组件里面发射出来的是Price类型的
  price:Price = new Price("",0);
}

6.修改app.component.html

<!-- 5.修改父组件模版 -->
<div>我是父组件</div>
<div>
  <!-- 双向绑定ngModel,在这个input上输入值的时候会改变stock的值 -->
  <input type="text" placeholder="请输入股票代码" [(ngModel)]="stock">
  <!-- 子组件里的stockCode属性的值为父组件的stock传入的 -->
  <app-order [stockCode]="stock" [amount]="100"></app-order>
</div>
<br>
<!-- 事件绑定,并传入当前的事件event,这里的lastPrice,对应@Output -->
<app-price (lastPrice) = "priceHandle($event)"></app-price>
<div>
    这是在报价组件外
</div>
<div>
    股票代码是{{price.stockCode}},股票价格是{{price.lastPrice | number:'2.2-2'}}
</div>

7.修改app.component.ts

import { Component } from '@angular/core';
import {Price} from "./price/price.component"


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  stock = "";
  //1.声明一个Price类型的属性,因为子组件里面发射出来的是Price类型的
  price:Price = new Price("",0);

  //2.声明priceHandle方法,在这个方法里接收一个event,这个event是Prive类型的
    //即这个类型是子组件emit方法发射出来东西的类型,即Price
  priceHandle(event:Price){
    this.price = event;
  }
}

8.结果

20.jpg

<3>中间人模式

中间人负责从一个组件中接收数据,并将其传递给另一个组件


如上图所示:
顶级中间人是1,组件1可使2、3、6互相通讯,是组件2、3、6的中间人;同理,组件2是4、5的中间人;组件3是7、8的中间人。

1.修改price.component.html

<div>
    这里是报价组件
</div>
<div>
    股票代码是{{stockCode}},股票价格是{{price | number:'2.2-2'}}
</div>
<!-- 新增一个购买按钮,绑定到一个购买事件,把event传进去 -->
<div>
    <input type="button" value="立即购买" (click)="buyStock($event)">
</div>

2.修改price.component.ts

import { Component, OnInit,EventEmitter,Output } from '@angular/core';

@Component({
  selector: 'app-price',
  templateUrl: './price.component.html',
  styleUrls: ['./price.component.css']
})
export class PriceComponent implements OnInit {
stockCode:string = "IBM";
price:number;

@Output()
lastPrice:EventEmitter<Price> = new EventEmitter();

//1.点击按钮时要把当前的价格发射出去
@Output()
buy:EventEmitter<Price> = new EventEmitter();

  constructor(){
    setInterval(()=>{
        let pr:Price = new Price(this.stockCode,100*Math.random());
        this.price = pr.lastPrice;
      this.lastPrice.emit(pr);
    },1000)
   }
   //2.定义buyStock方法,用buy的emit方法把当前价格信息发射出去
   buyStock(event){
     this.buy.emit(new Price(this.stockCode,this.price));
   }

  ngOnInit() {
  }

}
export class Price {
    constructor(public stockCode:string,
                public lastPrice:number
    ){}
}

3.修改order.component.ts--下单组件

/* 2.引入Input */
import { Component, OnInit,Input } from '@angular/core';

@Component({
  selector: 'app-order',
  templateUrl: './order.component.html',
  styleUrls: ['./order.component.css']
})
export class OrderComponent implements OnInit {
    /* 1.定义价格属性,用@Input装饰器注入 */
    @Input()
    price:Price;
  constructor() { }

  ngOnInit() {
  }

}

4.修改order.component.html

<!-- 3.修改模版 -->
<div>我是下单组件</div>
<div>
    买100只{{price.stockCode}}股票,价格是{{price.lastPrice | number:'2.2-2'}}
</div>

5.修改app.component.ts:用来接收price组件发射出来的价格和给order组件发送price信息

import { Component } from '@angular/core';
import {Price} from "./price/price.component"


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  stock = "";
  //1.声明一个Price类型的属性,因为子组件里面发射出来的是Price类型的
  price:Price = new Price("",0);

  //2.声明priceHandle方法,在这个方法里接收一个event,这个event是Prive类型的
    //即这个类型是子组件emit方法发射出来东西的类型
  priceHandle(event:Price){
    this.price = event;
  }
//3.声明buyHandle方法
  buyHandle(event:Price){
    this.price = event;
  }
}

6.修改app.component.html

<app-price (buy) = "buyHandle($event)"></app-price>

<!-- 下单组件 -->
<!-- 把price组件传过来的报价信息,通过属性绑定传给下单组件 -->
<app-order [price]="price"></app-order>

7.结果
点击购买按钮前

22.jpg

点击购买按钮后


23.jpg

<4>组件生命周期钩子

24.jpg

下面具体示例在项目中每个钩子的调用顺序
1.新建一个live组件

ng g component live

2.修改live.component.ts

import { Component, OnInit,OnChanges,DoCheck,AfterContentInit,
    AfterContentChecked,AfterViewInit,AfterViewChecked,OnDestroy,
    SimpleChanges,Input } from '@angular/core';

let logId:number = 1;

@Component({
  selector: 'app-live',
  templateUrl: './live.component.html',
  styleUrls: ['./live.component.css']
})
export class LiveComponent implements OnInit,OnChanges,
DoCheck,AfterContentInit,AfterContentChecked,
AfterViewInit,AfterViewChecked,OnDestroy {
    @Input()
    name:string;
    logIt(msg:string){
        console.log(`#${logId++} ${msg}`);
    }
  constructor() {
    this.logIt("name属性在constructor里的值是:"+name);
  }
  ngOnInit() {
    this.logIt("ngOnInit");
  }
  ngOnChanges(changes:SimpleChanges):void{
    let name = changes['name'].currentValue;
    this.logIt("name属性在OnChanges里的值是:"+name);
  }
  ngDoCheck():void{
    this.logIt("ngDoCheck");
  }
  ngAfterContentInit():void{
    this.logIt("ngAfterContentInit");
  }
  ngAfterContentChecked():void{
    this.logIt("ngAfterContentChecked");
  }
  ngAfterViewInit():void{
    this.logIt("ngAfterViewInit");
  }
  ngAfterViewChecked():void{
    this.logIt("ngAfterViewChecked");
  }
  ngOnDestroy():void{
    this.logIt("ngOnDestroy");
  }

}

3.修改app.component.html

<div>app组件</div>
<app-live [name]="title"></app-live>

4.结果

25.jpg

<5>OnChanges钩子

这个钩子会在父组件初始化或修改子组件的输入参数时会被调用

可变对象和不可变对象
在javascript中,字符串是不可变的,当一个字符串被创建在内存中时,它的值永远不会改变;而对象是可以改变的。例如:

var greeting = "hello";
//在内存中创建了一个值为hello的字符串
greeting = "hello world";
//在不改变第一个字符串的值的前提下创建了第二个值为“hello world”的字符串,这两个字符串都是不可变的,但是对于greeting这个变量来说,这个值是改变的,它指向的内存地址从第一个字符串的地址变为了指向第二个字符串的地址

var user = {"name",""tom};
//对象user的name属性指向了内存中值为"tom"的字符串。
user.name = "jane";
//一个新的字符串“jane”在另一个内存地址被创建,user的name属性指向了新的地址,但是user对象本身还是指向被创建时的内存地址。即改的是user对象的内容,而user指向的地址并没有变。上面的greeting是改变了指向的内存地址,这就是可变对象和不可变对象的区别。
示例
1.修改child.component.ts

import { Component, OnInit,Input,OnChanges,SimpleChanges } from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit,OnChanges {

  //1.定义三个属性,其中前两个是输入属性
  @Input()
  greeting:string;

  @Input()
  user:{name:string}

  mess:string = "初始化信息";
  constructor() { }

  ngOnInit() {
  }
  ngOnChanges(changes:SimpleChanges):void {
    console.log(JSON.stringify(changes, null, 2));
  }
}

2.修改child.component.html模版

<div style="background-color: #ddd;">
    <h2>我是子组件</h2>
    <div>问候语:{{greeting}}</div>
    <div>姓名:{{user.name}}</div>
    <!-- mess双向绑定 -->
    <div>消息:<input type="text" [(ngModel)] = "mess"></div>
</div>

要在app.module.ts中添加FormsModule

import { FormsModule } from '@angular/forms';
imports: [
    BrowserModule,
    FormsModule //此处添加
  ]

3.父组件需要给子组件传那两个输入属性,修改app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  greeting:string = "hello";
  user:{name:string} = {name:"tom"};
}

4.将那两个属性绑定到父组件模版中,修改app.component.html

<!-- <div>app组件</div>
<app-live [name]="title"></app-live> -->

<div>
    <h2>我是父组件</h2>
    <!-- 双向绑定 -->
    <div>
        问候语:<input type="text" [(ngModel)] = "greeting">
    </div>
    <div>
        姓名:<input type="text" [(ngModel)] = "user.name">
    </div>
</div>
<app-child [greeting]="greeting" [user]="user"></app-child>

结果

26.png

27.jpg

只有改变greeting时才会调用Onchanges

28.jpg
29.jpg

<6>变更检测和DoCheck钩子

DoCheck作用:保证组件属性的变化和页面的变化是一致的,浏览器中发生的任何异步事件都会触发变更检测

30.jpg

default策略:只要发生了变化,整个组件数都会被检查一遍
onpush策略:发生变化时,而子组件是onpush策略,就不会对
子组件进行检查,而是只有当子组件的输入属性发生改变时才会进行检查;
1.修改child.component.ts

import { Component, OnInit,Input,OnChanges,SimpleChanges,DoCheck } from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
//1.实现一个docheck钩子
export class ChildComponent implements OnInit,OnChanges,DoCheck {
  @Input()
  greeting:string;

  @Input()
  user:{name:string}

  mess:string = "初始化信息";


  oldUser:string;
  change:boolean = false;
nochange:number = 0;
  constructor() { }

  ngOnInit() {
  }
  ngOnChanges(changes:SimpleChanges):void {
    console.log(JSON.stringify(changes, null, 2));
  }
  ngDoCheck():void {
    if (this.user.name !== this.oldUser) {
        this.change = true;
        console.log("DoCheck:user.name从"+this.oldUser+"变为"+this.user.name);
        this.oldUser = this.user.name;
    }
    if(this.change){
        this.nochange = 0;
    }else {
        this.nochange = this.nochange + 1;
        console.log("docheck:user.name没变化时ngDocheck方法已经被调用"+this.nochange+"次");
    }
    this.change = false;
  }
}

结果
当点击父组件input框时,就会调用一次docheck,所以实现诸如带有check的钩子时要非常小心,实现要轻量级。

31.jpg

32.jpg

<7>view钩子

新的装饰器:@ViewChild
以下例子实现如何让父组件调用子组件的方法。
1.新建一个子组件

ng g component child2

2.修改child2.component.ts

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-child2',
  templateUrl: './child2.component.html',
  styleUrls: ['./child2.component.css']
})
export class Child2Component implements OnInit {

  constructor() { }

  ngOnInit() {
  }
  //1.写在子组件的方法
  greeting(name:string) {
    console.log("hello"+name);
  }

}

3.修改app.component.html

<!-- child1 、child2 是模版变量的名字 -->
<app-child2 #childone></app-child2>
<app-child2 #childtow></app-child2>

4.修改app.component.ts

import { Component,ViewChild} from '@angular/core';
import {Child2Component} from "./child2/child2.component"
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  //2.通过ViewChild装饰器+模版变量的名字来调用子组件的方法
  @ViewChild("childone")
  childone:Child2Component;

  ngOnInit():void {
    this.childone.greeting("tom");
  }

}

5.结果
控制台中可以看出父组件成功调用了子组件的greeing方法

33.png

方法二:在父组件的模版中调用子组件的方法
1.修改app.component.html

<!-- child1 、child2 是模版变量的名字 -->
<app-child2 #childone></app-child2>
<app-child2 #childtow></app-child2>

<button (click)="childtow.greeting('jane')"> 调用childtow的greeting方法</button>

2.结果
点击按钮时控制台中打印:hellojane

view钩子

这两个钩子会在组件模版内容都组装完,组件的内容已经呈现给用户看之后,被调用。
1.在父组件中实现这两个钩子,修改app.component.ts

import { Component,ViewChild,OnInit,AfterViewInit,AfterViewChecked} from '@angular/core';
import {Child2Component} from "./child2/child2.component"
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit,AfterViewInit,AfterViewChecked{
  title = 'Tom';
  greeting:string = "hello";
  user:{name:string} = {name:"tom"};

  //2.通过模版变量的名字来调用子组件的方法
  @ViewChild("childone")
  childone:Child2Component;

  ngOnInit():void {

     //定时调用子组件的greeting方法
     setInterval(() => {
       this.childone.greeting("tom");
     },5000 );
  }
  ngAfterViewInit():void {
    console.log("父组件的视图初始化完毕");
  }
  ngAfterViewChecked():void {
    console.log("父组件的视图变更检测完毕");
  }
}

2.在子组件中实现这两个钩子,修改child2.component.ts

import { Component, OnInit,AfterViewInit,AfterViewChecked } from '@angular/core';

@Component({
  selector: 'app-child2',
  templateUrl: './child2.component.html',
  styleUrls: ['./child2.component.css']
})
export class Child2Component implements OnInit,AfterViewInit,AfterViewChecked {

  constructor() { }

  ngOnInit() {
  }

  ngAfterViewInit():void {
    console.log("子组件的视图初始化完毕");
  }
  ngAfterViewChecked():void {
    console.log("子组件的视图变更检测完毕");
  }


  greeting(name:string) {
    console.log("hello"+name);
  }

}

3.结果
控制台中,子组件的组件先被组装好,childone和childtwo组件被组装好之后,父组件才被组装好。ngAfterViewInit只会被调用一次。当每隔5秒,父组件调用子组件greeting方法时,触发变更检测机制,两个子组件和父组件的ngAfterViewChecked又被调用。

34.jpg

注意:不要在这两个方法中改变视图中绑定的数据,否则会抛出异常

35.jpg

解决方案:放到另一个javascript的运行周期中,例如:

36.jpg

<8>ngContent指令

说在前面:投影
当希望运行时动态改变模版的内容,就可以用ngContent指令将父组件模版中的任意片段投影到子组件上。

示例1:当投影单个片段时
1.在子组件中,修改child.component.html

<div style="background-color: #aaa">
    <p>下面是子组件内容</p>
    <!-- 子组件中使用ng-content标签 -->
    <ng-content></ng-content>
</div>

2.父组件中,修改app.component.html

<div style="background-color: #eee;padding: 20px;">
  <div>下面是父组件内容</div>
  <!-- 父组件中,将要投影的内容写在子组件标签内 -->
  <app-child>
      这里是父组件投影到子组件的内容
  </app-child>
</div>

示例2:当投影多个片段时
1.修改app.component.html

<div style="background-color: #eee;padding: 20px;">
  <div>下面是父组件内容</div>
  <!-- 父组件中,将要投影的内容写在子组件标签内 -->
  <app-child>
    <!-- 投影多个片段时,分别给不同div指定样式,用来区分投影点 -->
    <div class="header">这是页头,是父组件投影到子组件的内容</div>
    <div class="footer">这是页尾,是父组件投影到子组件的内容</div>
  </app-child>
</div>

2.修改child.component.html

<div style="background-color: #aaa">
    <p>下面是子组件内容</p>
    <!-- 子组件中使用ng-content标签 -->
    <ng-content select=".header"></ng-content>
    <div>子组件中间内容</div>
    <ng-content select=".footer"></ng-content>
</div>

3.结果

37.jpg

<9>AfterContentInit和AfterContentChecked指令

AfterContentInit和AfterContentChecked是被投影的内容被组装完毕时调用的,与AfterViewInit不同的是,在AfterContentInit中可以改变视图中绑定的数据。
示例:
1.修改app.component.ts

import { Component,AfterContentInit,AfterContentChecked,AfterViewInit } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterContentInit,AfterContentChecked,AfterViewInit {
message = "hi";
    ngAfterContentInit():void {
console.log("父组件投影内容初始化完毕");
//此处改变了视图中绑定的数据,控制台中不报错
this.message = "jane";
}
ngAfterContentChecked():void {
console.log("父组件投影内容变更检测完毕");
}
ngAfterViewInit():void {
console.log("父组件视图内容初始化完毕");
}

  title = 'app';
}

2.修改child.component.ts

import { Component, OnInit,AfterContentInit,AfterContentChecked } from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit,AfterContentInit,AfterContentChecked {
ngAfterContentInit():void {
console.log("子组件投影内容初始化完毕");
}
ngAfterContentChecked():void {
console.log("子组件投影内容变更检测完毕");
}
  constructor() { }

  ngOnInit() {
  }

}

3.结果

38.png

<10>ngOnDestroy

当从一个路由地址跳往另一个路由地址时,前一个路由地址对应的组件会被销毁,而后一个路由地址对应的组件会被创建。
示例:
1.新建一个项目,并创建两个子组件

ng new destroyPro
ng g component child
ng g component child2

2.修改app.module.ts,定义一些路由

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';


import { AppComponent } from './app.component';
import { ChildComponent } from './child/child.component';
import { Child2Component } from './child2/child2.component';
//3.引入routes和RouterModule
import  {Routes,RouterModule} from "@angular/router";



//1.当路径为空时,显示child组件内容,当路径为child2时显示child2内容
var routeCongif:Routes = [
  {path:'',component:ChildComponent},
  {path:'child2',component:Child2Component}

]

@NgModule({
  declarations: [
    AppComponent,
    ChildComponent,
    Child2Component
  ],
  //2.把路由配置导入模块
  imports: [
    BrowserModule,
    RouterModule.forRoot(routeCongif)
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

3.修改app.component.html

<a [routerLink] = "['/']">child</a>
<a [routerLink] = "['/child2']">child2</a>
<!-- 插座 -->
<router-outlet></router-outlet>

4.修改child.component.ts和child2.component.ts,实现OnDestroy方法

import { Component, OnInit,OnDestroy } from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit,OnDestroy {

ngOnDestroy():void {
    console.log("child组件已被销毁");
}
  constructor() { }

  ngOnInit() {
  }

}

import { Component, OnInit,OnDestroy } from '@angular/core';

@Component({
  selector: 'app-child2',
  templateUrl: './child2.component.html',
  styleUrls: ['./child2.component.css']
})
export class Child2Component implements OnInit,OnDestroy {
ngOnDestroy():void {
    console.log("child2组件已被销毁");
}
  constructor() { }

  ngOnInit() {
  }

}

5.结果
当点击路由切换时

39.png

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,644评论 18 139
  • 此文基于官方文档,里面部分例子有改动,加上了一些自己的理解 什么是组件? 组件(Component)是 Vue.j...
    陆志均阅读 3,813评论 5 14
  • 学习资料来自 Angular.cn 与 Angular.io。 模板语法 在线例子 在 Angular 中,组件扮...
    小镭Ra阅读 3,727评论 0 3
  • 一.课程简介 (注意:这里的AngularJS指的是2.0以下的版本) AngularJS的优点: 模板功能强大丰...
    壹点微尘阅读 915评论 0 0
  • 今年22岁了,回忆过去发现有很对的遗憾,但是世界是没有后悔药吃的,所以只能认命继续改变你自己的命运,想命运低头,...
    kddy阅读 151评论 0 1