typescript笔记

一、ts介绍

是javascript的超集,遵循最新的ES5 ES6规范。ts扩展了js的语法。

二、安装与编译

Npm install -g typescript cnpm install -g typescript yarn global add typescript
查看安装成功与否 新打开终端 输入:tsc -v
运行: tsc helloword.ts

vscode编译:因为浏览器不认识ts代码需要我们编译, 在终端输入tsc + 文件名.后缀 会在同级生成一个以js结尾的文件
为了节省开发时间,每次写好ts代码后能够自动编译

1.创建ts.config.json的文件 tsc --init 生成配置文件 修改配置文件中outDir可配置编译后的Js存放位置
2.vscode点击:任务->运行任务-> tsc:监视-tsconfig.json(老版本vscode)
终端-> 运行任务-> typescript -> 监视tsconfig.json 即可

三、数据类型

ts中为了使编码更规范,更有利于维护,增加了类型校验:
布尔类型(bollean)
数字类型(number)
字符串类型(string)
数组类型(array)
元组类型(tuple)
枚举类型(enum)
任意类型(any)
null和undefined
void类型
never类型

1.布尔类型
eg. var flag:boolean=true 如果写falg = “str”,编译不通过会报错
2.数字类型(整数、浮点数都ok)
Var a:number = 123
3.字符串类型
4.数组类型 OK 有两种方式
方式一:let arr:nuber[] = [1, 2, 3, 4]
方式二:let arr:Array<number>=[11, 23, 353, 34]
5.
元组类型
(属于数组的一种,可以指定数组中每一项的多种类型)
Let arr:[string, number, boolean] = [“ts”, 1, true]
6.**枚举类型 ** (用于标识状态和固定值)
随着计算机的不断普及,程序不仅只用于数值计算,还更广泛用于处理非数值的 数据。例如:性别、月份、颜色、单位、学历等,都不是数值数据。
事先考虑到某一变量可能去的值,尽量用自然语言中含义清楚的单词来表示他的每一个值,这种方法称为枚举方法

enum 枚举名{
  标识符[=整型常数],
  标识符[=整型常数],
  ...
  标识符[=整型常数]
}
Enum flag {
  Success=1,
  Error=-1
}
Let f:flag = flag.success   /   flag.error就代表一个值

若枚举中没有赋值的话,会输出占位的索引

如果是:

Enum color {red, blue=5, orange} 
Let c:color=color.red    输出c为其索引 0
Let c:color = color.blue  输出c为其值 5
Let c:color = color.orange  输出c为 6   自动跟随前一个进行累加 

7.任意类型 any

Let num:any=123
Num=”str”  

用于获取节点之后操作dom可以使用any类型

8.**null undefined **(其他never类型的子类型)
如果定义了变量未赋值,输出个该变量为undefined 但是会报错
所以要声明变量的时候,在变量后加undefined
如果是该变量可能是number 也可能是undefined 就 let num:number | undefined

null也是如此

一个元素是多种类型,any类型可以囊括这些内容,还有一个其他形式:
Let num:number | null | undefiend

9.void类型 :表示没有任何类型,一般用于定义方法的时候方法没有返回值

Function run():void {
  Console.log(‘run’)
}
run();

10.never类型 是其他类型,(null undefined的子类型)代表不会出现的值。意味着声明never的变量只能被never类型所赋值

Let a:undefined;
a = undefined

Let b:null;
b = null;

Let a :never;
a=132;  //错误写法
a =(() => { 
  Throw new Error(‘错误”)
})()    //正确写法

四、函数

函数也是需要指明类型的

//函数声明类
function run():string {
  return 'run'
}
fun2();

//匿名函数
var fun2=function():number {
  return 123
}
fun2();

ts中定义方法传参

//函数声明
function getInfo(name: string, age:number):string {
  return `${name} --- ${number}`
}

console.log(getInfo('zhangsan', 20));

//匿名函数
let getInfo2 = function(name: string, age:number):string {
  return `${name} --- ${number}`
}
console.log(getInfo('zhangsan', 20));

没有返回值得函数

function run():void {
  console.log('run')
}
run();

方法的可选参数
es5方法的实参和形参可以不一样,但是ts不可以,此时需要配置可选参数
即在可能不会传递的参数后面添加 ?

function getInfo(name: string, age?:number):string {
  if (age) {
    return `${name} --- ${number}`
  } else {
     return `${name} --- 就不告诉你 `
  }
}

//alert(getInfo('张三', 123))   都可输出
//alert(getInfo('张三'))  都可输出

注意:可选参数必须配置到参数的最后面

默认参数
es5里面没法设置默认参数,es6和ts都可以设置默认参数

function getInfo(name: string, age:number=12):string {
  if (age) {
    return `${name} --- ${number}`
  } else {
     return `${name} --- 就不告诉你 `
  }
}

//alert(getInfo('张三'))  都可输出,且age是默认的
//alert(getInfo('张三', 123))   都可输出

剩余参数

function sum(a: number, b:number, c:number, d:number):number {
    return a + b+c+d
}

sum(1, 2, 3, 4)

//三点运算符(剩余参数)  接受形参传来的值
function sum(...result:number[]):number {
    let sum = 0;
    for(var i = 0; i < result.length; i ++) {
      sum += result[i];
    }
  return sum
}

sum(1, 2, 3, 4, 5, 6)

//剩余参数三点运算另一种形式
function sum(a:number, ...result:number[]):number {
    let sum = a;
    for(var i = 0; i < result.length; i ++) {
      sum += result[i];
    }
  return sum
}

sum(1, 2, 3, 4, 5, 6)

函数重载
java中方法的重载,重载的是两个或两个以上同名函数,但他们的参数不一样,这时会出现函数重载的情况
ts中的重载,通过为同一个函数提供多个函数类型定义来试下多种功能的目的
ts为了见佛那个es5和es6 重载的写法 和java有区别

//es5中 出现同名方法,后面的会替换上面的方法
function css(config:any):any {
  ...
}

function css(config:any, value:any):any {
  ...
}


//ts中的重载
function getInfo(name: string):string;
function getInfo(age: number):number;
function getInfo(str: any):any {
  if(typeof str === 'string') {
    return '我是,’+ str;
  } else {
    return ‘我的年龄是,’ + str
  }
}

alert(getInfo('张三'))  //正确
alert(getInfo(12))  //正确
alert(getInfo(true))  //错误


//----------------------------------------------
//参数一样
function getInfo(name: string):string;
function getInfo(name: string, age: number):string;
function getInfo(name: string, age?:any):any {
  if (age) {
    return '我叫,' + name + '我的年龄是' + age;
  } else {
    return '我叫, ' + name
  }
}
alert (getInfo('张三'))    //正确
alert (getInfo(123))    //错误
alert (getInfo('张三', true))    //错误

箭头函数

this指向的问题, 箭头函数的this指向上下文

//es5
setTimeout(function() {
  alert('run')
}, 1000)

//箭头函数     
setTimeout(() => {
  alert('run')
}, 1000)

五、ts中的类

  1. 通过class类来定义
class Person {
  name:string;    //属性   前面省略了public关键词
  constructor(n:string) {   //构造函数  实例化类的时候触发的方法
    this.name = n;
  }

  run():void {
    alert(this.name);
  }
}

let p = new Person('张三');
p.run();
class Person {
  name: string;   
  constructor(name: string) {   
    this.name = name;
  }

  getName():string {
    return this.name;
  }

  setName():void {
    this.name = name;
  }
}

let  p = new Person('张三')
alert(p.getName());
p.setName('李四')
alert(p.getName());
  1. ts中实现继承 extends / super
class Person {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  run():void {
    return `${this.name}在运动`
  }
}

//继承
class Web extends Person {
  constructir(name: string) {
    super(name);    /*初始化父类的构造函数*/
  }

let w = new Web('李四');
alert(w.run());
  1. ts中继承 父类的方法和子类的方法一致
    如果父类和子类都有同样的方法 调用子类的就会执行子类方法,先去找子类再找父类

  2. 类里的修饰符
    提供了三种修饰符

  • public : 表示共有。 在当前类里面、子类、类外部都可以访问
  • protected: 表示保护类型。 在当前类里面、子类里面可以访问, 类外部无法访问 //控制台会报错,但是会输出,
  • private: 表示私有。 在当前类里面可以访问,子类和类外部都无法访问
    属性如果不加修饰符 默认为共有public
class Person {
  public  name: string;      //公有属性
  constructor(name: string) {   
    this.name = name;
  }

  run():string {
    return `${this.name}在运动`
  }
}

class Web extends Person {
  constructir(name: string) {
    super(name);    /*初始化父类的构造函数*/
  }

let w = new Web('李四');
alert(w.run());

  1. 静态属性 静态方法
class Person {
  public name: string
  public age: number=12
  
  //静态属性才能在静态方法中调用
 static sex = "男"

  constructor(name:string) {
    this.name = name
  }

  run() {
    alert(`${this.name}在运动`)                //实例方法
  }

  work() {
    alert(`${this.name}在工作`)                //实例方法
  }

  //静态方法   没法直接调用类里的属性  
  static print() {
    alert('方法' + this.age)      //会报错
  }

static print() {
    alert('方法' + Person.sex)      //调用成功
  }
}

let p = new Pweson('张三');
p.run();
p.work();

//调用静态方法
Person.print();

//使用静态属性
alert(Person.sex)
  1. 多态:父类定义一个方法不实现,让继承他的子类去实现 每一个子类有不同的表现
    //多态也是一种继承的表现,属于继承
class Animal {
    name:string;
    constructor(name: string) {
        this.name = name
    }
    
    eat() {
        console.log('吃的方法')
    }
}

class Dog extends Animal {

    construactor(name: string) {
        super(name)
    }

    eat() {
        return this.name + '吃狗粮'
    }
}


class Cat extends Anmal  {

    construactor(name: string) {
        super(name)
    }

    eat() {
        return this.name + '吃猫粮'
    }
}
  1. 抽象类:它是提供其他类继承的基类,不能直接被实例化
    abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含其具体实现并且必须在派生类中实现 abstract抽象方法只能放在抽象类里面 抽象类和抽象方法用来定义标准
//抽象类和抽象方法用来定义标准  标准:Animal这个类要求他的子类必须包含eat方法
abstract class Animal {

   abstract eat():any;
}

let a = new Animal()   //错误的写法   不能直接被实例化

image.png

image.png

正确写法

//抽象类和抽象方法用来定义标准  标准:Animal这个类要求他的子类必须包含eat方法
abstract class Animal {
  public name:string;
  constructor(name:string) {
      this.name = name;
  }
   abstract eat():any;   //该方法必须实现

    run() {
      console.log('其他方法可以不实现')
    }
}

let a = new Animal()   //错误的写法

class Dog extends Animal {

    constructor(name:any) {
       super (name);
  }

    //抽象类的子类必须实现抽象类里面的抽象方法
    eat()  {
        console.log(this.name + '吃粮食')
     }
}

let d = new Dog('小花花');
d.eat();

六、ts中的接口

接口的作用:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范作用,接口起到一种限制和规范的作用,接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它之规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。ts中的接口类似于java,同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等。 相当于定义标准。

通过interface进行定义

  1. 属性类接口
  • 对传入对象参数进行约束
//就是传入对象的约束   是属性接口
interface FullName {

    firstNmae: string;       //注意  以分号结束
    secondName: string; 

}
function printName(name:FullName) {
    
    //必须传入对象   firstName  secondName
    console.log(name.firstName + '--' + name.secondName)

}

printName('123')  //错误的写法
printName({firstName: '张', secondName: '三'})    //正确
printName({ age: 20, firstName: '张', secondName: '三'})    //错误写法  因为多了age,内容必须只有firstName和secondName
let obj = {
  age: 20,     //但是当调用的时候就会报错
  firstName: '张',
  secondName: '三'
}
printName(obj);     //正确写法  且推荐此使用   外层定义只要有firstName和secondName就行
  • 对批量方法进行约束
interface FullName {

    firstNmae: string;       //注意  以分号结束
    secondName: string; 

}
function printName(name:FullName) {
    
    //必须传入对象   firstName  secondName
    console.log(name.firstName + '--' + name.secondName)

}

function printInfo(name:FullName) {
    
    //必须传入对象   firstName  secondName
    console.log(name.firstName + name.secondName )

}

let obj = {
  age: 20,     
  firstName: '张',
  secondName: '三'
}
printName(obj); 

printInfo({firstName: '李', secondName: '四'})

  1. 可选属性
interface FullName {
    firstName: string;
    secondName?: string;     //可传可不传
}

function getName(name: FullName)  {
    console.log(name)
}

getName({firstName: 'xixixi', secondName: '啦啦'})
getName({firstName: 'xixixi'})   //也可编译成功
  1. 函数类型接口: 对方法传入的参数 以及返回值进行约束 可以做批量约束
//实现加密的函数类型接口
interface encrypt {
  (key: string, value: string): string;    //参数是key和value   返回值是string类型
}

let md5:encrypt = function(key: string, value: string):string {
    //模拟操作
    return key + value
}

md5('name', 'zhangsan')
  1. 可索引接口,数组、对象的约束(不常用)
//定义数组的方式
let arr:number[] = [123, 34555]
let arr1:Array<string>=['23g', 'err4']

//可索引接口 对数组的约束 1
interface UserArr {
  [index: number]:string
}
let arr:UserArr=['aaaa', 'bbbb'];
console.log(arr[0])

//对对象的约束
interface UserObj{
  [index:string]:string
}
let arr:UserObj = {name: '20'}
  1. 类类型接口:对类的约束 和 抽象类相似
    implements不是继承,是实现接口
interface Animal {

    name: string;

    eat(str: string):void;

}

class Dog implements Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }

  eat() {
    console.log(this.name + '吃狗粮')
  }
}

let d = new Dog('小黑')
d.eat();


class Cat implements Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }

  eat(food:string) {
    console.log(this.name + food)
  }
}

let c = new Cat('小花')
d.eat('老鼠')
  1. 接口扩展,接口可以继承接口
interface Animal {
  eat(): void;
}
interface Person extends Animal {     //person继承animal
  work();
}

class Web implements Person {
    public name:string;
    constructor(name: string) {
        this.name = name
    }

    eat() {
        console.log(this.name + '喜欢吃馒头')
    }

    work() {
      console.log(this.name + '喜欢工作')
    }
}

let w = new Web('小李')
w.eat()
interface Animal {
  eat(): void;
}
interface Person extends Animal {     //person继承animal
  work();
}

class Programmer {
    public name:string;
    constructor(name: string) {
        this.name = name
    }
    coding(code:string) {
      console.log(this.name + code)
    }
}

class Web extends Programmer  implements Person {   //既继承又实现接口

    constructor(name: string) {
        super(name)
    }

    eat() {
        console.log(this.name + '喜欢吃馒头')
    }

    work() {
      console.log(this.name + '喜欢工作')
    }
}

let w = new Web('小李')
w.eat()
w.coding('写ts代码')

七、ts中的泛型

  1. 泛型的定义
    泛型:软件工程中,我们不仅要创建一致的定义好的API,同时也要考虑重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。

在像C#和java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。这样用户就可以以自己的数据类型来使用组件。

通俗理解:泛型就是解决 类、接口、方法的复用性、以及对不特定数据类型的支持

  1. 泛型函数
//例如同时返回两个不同类型的函数  容易代码冗余
function getData1(value: string):string {
  return value;
}

function getData2(value: number): number {
  return value
}

//可以使用any类型来进行同时输出,但是使用any放弃了类型检查,传入什么,返回什么
//泛型就出现了

泛型可以支持不特定的数据类型 要求,传入的参数和返回的参数一致。
T或者是任意大写字母。(建议使用T)表示泛型,具体什么类型是调用这个方法的时候决定的

function getData<T>(value: T):T {
  return value;
}

getData<number>(123);
function getData<T>(value: T): any {
  return 'sfdsfgfdgdfg'
}
getData<number>(123);     //参数必须是number
getData<string>('dfdsfdsfg');
  1. 泛型类
//泛型类: 比如有个最小堆算法,需要同时支持返回数字和字符串两种类型   通过类的泛型来实现
class MinClass {

    piblic list:number[] = [];

    add(num: number) {
        
       this.list.push(num)
    }

    min() {

      let minNum = this.list[0];
    }

}

  1. 泛型接口

//函数类型接口
interface ConfigFn{
    (value1: string, value2: string): string;
}

let setData:ConfigFn = function(value1: string, value2: string):string {
    retirn value1+value2;
}

setData('name': '张三')


//第一种泛型接口

interface ConfigFn{
    <T>(value: T): T;
}

let getData: ConfigFn = function<T>(value: T):T {
    return value;
}
 
getData<string>('张三')     //正确
getData<string>(1234)   //错误


//第二种泛型接口
interface ConfigFn<T>{
    (value: T): T;
}

function getData<T>(value: T):T {
    return value;
}

let myGetData:ConfigFn<string>=getData;

myGetData('20');    //正确
myGetData(20);    //错误
  1. 泛型类--延伸
    1.定义个User类 作用:隐射数据库字段
    2.定义个MysqlDb的类 用于操作数据库
    3.然后把User类作为参数传入到MysqlDb中
//把类作为参数来约束数据传入的类型
class User {
    username: string | undefined;
    password: string | undefined;
}

class MysqlDb {
    add(user: User): boolean {
      // console.log(user);
      return true;
    }
}

let u = new User();
u.username = '张三';
u.password = '123456';

let Db = new MysqlDb();
Db.add(u);
//把类作为参数来约束数据传入的类型
class ArticleCate {
    title: string | undefined;
    desc: string | undefined;
    status: number | undefined;
}

class MysqlDb {
    add(info: ArticleCate): boolean {
      // console.log(info);
      return true;
    }

    updated(info: T, id: number): boolean {
        console.log(info)
        console.log(id)
        return true
    }
}

let a= new ArticleCate();
a.title = "国内";
a.desc = "国内新闻";
a.status = 1
let Db = new MysqlDb();
Db.add(a);

发现以上两种写法在每操作一次数据库表的时候 都需要重新指定值得类型,所以使用泛型动态的定义类型,避免代码重复封装

//操作数据库的泛型类
class MysqlDb<T> {
    add(info: T): boolean {
      // console.log(info);
      return true;
    }
}

//给User表增加数据
//1.定义一个user类 和数据库进行映射
class User {
    username: string | undefined;
    password: string | undefined;
}
let u = new User();
u.username = '张三';
u.password = '123456';


let Db = new MysqlDb<User>();    //可以对传入的数据进行校验
Db.add(u);   


//赋值方式2    使用构造函数将值提前赋进去
class User {
    username: string | undefined;
    password: string | undefined;
    constructor(params: {
       username: string | undefined,
       password: string | undefined,
      //或者是可选参数 记得加?
    }) {
        this.username = params.username;
        this.password = params.password;
    }
}

let u = new User({
    username: '张三',
    password: '123456'
});

let Db = new MysqlDb<User>();    //可以将类作为参数传入到泛型类中进行数据的约束及验证
Db.add(u);   
  1. ts类型、接口、类、泛型综合使用--ts封装统一操作Mysql Mongodb Mssql的底层库
    定义一个操作数据库的库 支持Mysql Mongodb Mssql
    要求1 Mysql Mongodb Mssql功能一样 都有add update delete get方法
    注意:约束统一的规范,以及代码重用
    解决方案:需要约束规范所以要定义接口,需要代码重用所以用到泛型
    1.接口:在面向对象的编程中,接口是一种规范性的定义,它定义了行为和动作的规范
    2.泛型 通俗理解:泛型就是解决 类 接口 方法的复用性
interface DBI<T> {
    add(info: T): boolean;
    update(info: T, id: number): boolean;
    delete(id: number): boolean;
    get(id: number): any[];
}

//定义一个操作mysqul数据库的类  注意:要实现泛型接口  这个类也应该是一个泛型类
class MysqlDb<T> implements DBI<T> {

    constructor() {
        console.log('数据库建立连接')
    }

    add(info: T): boolean {
       console.log(info)
        return true
    }

    update(info: T, id: number): boolean {
        throw new Error('Method not implemented')
    }

    delete(id: number): boolean {
        throw new Error('Method not implemented')
    }
    
    get(id: number): any[] {
        let list = [
          {
              title: ‘xxx’,
              desc: 'xxxxx'
          },
           {
              title: ‘xxx’,
              desc: 'xxxxx'
          },
        ]
      return list;
    }
}

//定义一个操作mssqul数据库类型的类
class MsSqlDb<T> implements DBI<T> {

    constructor() {
        console.log('数据库建立连接')
    }
    add(info: T): boolean {
        throw new Error('Method not implemented')
    }

    update(info: T, id: number): boolean {
        throw new Error('Method not implemented')
    }

    delete(id: number): boolean {
        throw new Error('Method not implemented')
    }
    
    get(id: number): any[] {
        throw new Error('Method not implemented')
    }
}

//操作用户表 定义一个类和数据表做映射
class User {
    username: string | undefined;
    password:  string | undefined;
}

let u = new User();
u.username = '战三';
u.password = "123456";

let oMysql = new MysqlDb<User>();
oMysql.add(u)

八、ts中的模块

模块的概念(官方)
关于属于的一点说明:ts1.5里的术语名已经发生了变化。 “内部模块”现在称作“命名空间”。“外部模块”现在简称为“模块” 模块在其自身的作用域里执行,而不是在全局作用域里。
这意味着定义在一个模块里的变量,函数,类等等在模块外部是不可见的,除非你明确的使用export形式一导出他们。相反,如果想使用其他模块导出的变量,函数、类、接口等的时候,你必须要导入他们,可以使用import形式之一

模块的概念(自己的理解)
我们可以把一些公共的功能单独抽离成一个文件作为一个模块。
模块里面的变量 函数 类等默认是私有的,如果我们要在外部访问模块里面的数据(变量、函数、类)
我们需要通过export暴露莫苦熬里面的数据(变量、函数、类)。
暴露后通过import引入模块就可以使用模块里面暴露的数据(变量、函数、类)

引用名字过长的时候 可以使用 xx as aa来,此后调用使用aa代替xx即可

import { getData as get } from './......'

你是前端嘛?是的话,我就不用写了 和js没差的 不是的话 那你就先成为一个前端再看吧

九、ts的命名空间

在代码量较大的情况下,为了避免各种变量命名冲突,可将相似功能的函数、类、接口等放置到命名空间,可以将代码包裹起来,只对外暴露需要外部访问的对象,命名空间内的对象通过export暴露

命名空间和模块的区别
命名空间:内部模块,主要用于组织代码,避免命名冲突
模块:ts的外部模块简称,例如代码的复用,一个模块里可能有多个命名空间

namespace A {...........}   //定义了一堆内容
namespace B {...........}   //定义了一堆内容  两者中的内容可以有重复的

如果想要外部暴露,可以在需要暴露的内容前面加export,使用可以通过命名空间打点使用内部内容即可
把命名空间定义成模块并且暴露使用

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