ts学习笔记

配置

  • tsc --init 生成tsconfig.json
  • vscode 任务-运行任务 tsc:监视-tsconfig.json

数据类型

  • boolean, number, string, array, null, undefied, void

  • 元组类型tuple

    let tuple:[number, string] = [1, 's']
    
  • 枚举类型enum

    enum Color {
        red,
        blue,
        yellow = 5,
    }
    let color:Color = Color.yellow // 5
    color = Color.yellow // 0, 未赋值则输出下标
    
  • 任意类型any

  • null和undefined是其他(never)类型的子类型

  • void类型: ts中void类型表示没有任何类型,一般用于定义方法时,方法没有返回值

  • never类型:其他类型(null和undefined)的子类型

函数

// 函数声明
function run():string {
    return '123'
}

// 匿名表达式
var run2 = function():string {
    return '123'
}

// ts中定义方法传参
function getInfo(name: string, age: number):string {
    return `${name}:${age}`
}

// 方法可选参数(age可传,可不传)
// 可选参数要放在所有参数的最后
function getInfo(name: string, age?: number):string {
    if (age) {
        return `${name}:${age}`
    }
    return `${name}`
}

// 默认参数
function getInfo(name: string, age: number = 20):string {
    if (age) {
        return `${name}:${age}`
    }
    return `${name}`
}

// 剩余参数
function sum(a: number, b:number, c:number, d:number):number {
    return a + b + c + d;
}
可改为
function sum(...res: number[]):number {
  return res.reduce((acc, cur) => acc + cur, 0)
}

// ts函数重载
function getInfo(name: string): string;
function getInfo(age: number): number;

function getInfo(arg: any): any {
  return 123;
}
// 箭头函数

ts中的类

  • 类的定义、继承
// es5
function Person(name) {
  this.name = name;
  this.run = function () {
    console.log(this.name)
  }
}
var p = new Person('张三')
p.run()


// ts中定义类
class Person {
  name: string; // 属性,省略了public关键词
  constructor(name:string) { // 构造函数,实例化类时触发的方法
    this.name = name;
  }
  getName():string {
    return this.name
  }
  setName(name: string):void{
    this.name = name
  }
}

var p = new Person('张三')
p.setName('李四')
alert(p.getName())

// ts中实现继承 extends, super

class Person {
  name: string; // 属性,省略了public关键词
  constructor(name:string) { // 构造函数,实例化类时触发的方法
    this.name = name;
  }
  run():string {
    return `${this.name} is running`
  }
}

class Web extends Person {
  constructor(name: string) {
    super(name)
  }
}

var w = new Web('lisi')
console.log(w.run())

// ts中继承的探讨
class Person {
  name: string; // 属性,省略了public关键词
  constructor(name:string) { // 构造函数,实例化类时触发的方法
    this.name = name;
  }
  run():string {
    return `${this.name} is running`
  }
}

class Web extends Person {
  constructor(name: string) {
    super(name)
  }
  run():string {
    return '子类' //父类中也有同名方法,则调用子类的方法
  }
  work() {
    alert(`${this.name}在工作`) // this指向web实例
  }
}

var w = new Web('lisi')
console.log(w.run())

类里的修饰符

  • ts里定义属性的时候,给我们提供了三种修饰符
/* 
    public:公有 在类里面,子类和类外面都可以访问
    protected:?;だ嘈?在类里面、子类里面可以访问,在类外部没法访问
    private:私有 在类里面可以访问,子类和类外部都没法访问
*/

// public
// 属性不加任何修饰符为public

// 类外部访问公有属性
class Person {
  public name: string;
  constructor(name:string) {
    this.name = name;
  }
}
var p = new Person('lala');
console.log(p.name)

// protected

// 在子类中访问
class Person {
  protected name: string; // 属性,省略了public关键词
  constructor(name:string) { // 构造函数,实例化类时触发的方法
    this.name = name;
  }
}
class Web extends Person {
  constructor(name: string) {
    super(name)
  }
  run():string {
    return `${this.name}lalalla`
  }
}
var w = new Web('ab');
console.log(w.run())

// private 只能在类内部访问
class Person {
  private name: string; // 属性,省略了public关键词
  constructor(name:string) { // 构造函数,实例化类时触发的方法
    this.name = name;
  }
}


静态属性 静态方法

  • es5
// 实例方法
function Person() {
  this.run1 = function() {
    ...
  }
}

// 静态方法
Person.run2 = function() {

}

// 静态属性
Person.name = 'lalal'


var p = new Person();
p.run1()

Person.run2()
  • 已经有实例方法,为啥要有静态方法

    // jquery
    
    function $(element) {
        return new Base(element)
    }
    
    function Base (element) {
        this.element = document.getElementById(element);
        this.css = function (attr, val) {
            this.element.style.attr = val
        }
    }
    // 实例方法
    $('#box').css('color', 'red')
    // 静态方法
    $.get('url', function() {...})
    
  • ts里静态方法和属性

class Person {
  public name: string
  public age: number = 20
  // 静态属性
  static sex: string = '男'
  constructor(name:string) {
    this.name = name;
  }
  // 实例方法
  run() {
    alert(`${this.name}is running`)
  }
  work() {
    alert(`${this.name}is working`)
  }
  // 静态方法 里面没法直接调用类里面的属性!??!
  static print() {
    alert(`print+${Person.sex}`)
  }
}

Person.print()

多态 :父类定义一个方法不去实现,让继承他的子类去实现,每一个子类有不同的表现

  • 多态属于继承
class Animal {
  name: string
  constructor(name: string) {
    this.name = name
  }
  eat() { // 具体的内容,让继承他的子类去实现,每个子类有不同表现
    console.log('eat')
  }
}

class Dog extends Animal {
  constructor(name: string) {
    super(name)
  }
  eat() {
    return this.name + '吃肉'
  }
}

class Cat extends Animal {
  constructor(name: string) {
    super(name)
  }
  eat() {
    return this.name + '吃鱼'
  }
}

var cat = new Cat('cattie')
alert(cat.eat())

ts中的抽象类,提供其他类继承的基类,不能直接被实例化

  • 用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并必须在派生类中实现
  • abstract抽象方法只能放在抽象类里面
  • 抽象类和抽象方法用来定义标准
// Animal类的子类必须包含eat方法
abstract class Animal {
  public name: string;
  constructor(name:string) {
    this.name = name
  }
  abstract eat():any;
}

// 抽象类的子类必须实现抽象类里的抽象方法
class Dog extends Animal {
  constructor(name:string) {
    super(name)
  }
  eat() {
    return this.name + 'something'
  }
}

var d = new Dog('abctest+')
alert(d.eat())

ts中的接口

  • 定义标准(包括属性,函数,可索引, 类等)

属性接口 对json的约束

// 接口 行为和动作的规范 对批量方法传入参数进行约束
// 对传入对象的约束, 属性接口
interface FullName {
  firstName: string; // 注意??!分号结束
  secondName: string;
}

function printName(name: FullName) {
  // 必须传入对象,必须包含fistName,secondName
  console.log(`${name.firstName} ${name.secondName}`)
  // console.log(`${name.firstName} ${name.secondName} ${name.age}`) // name.age 报错
}

// 直接传入参数,则有且仅有firstName和secondName,否则报错
// printName({ firstName: 'zhang', secondName: 'san' age: 20 }) // age报错

// 定义在外面 再传入,则必须包含firstName和secondName,多的参数也行, 但在方法里调用fullName不存在的属性也会报错
const obj = {
  firstName: 'zhang',
  secondName: 'san',
  age: 20
}

printName(obj)
  • 接口 可选属性
interface FullName {
  firstName: string;
  secondName?: string;
}

函数类型接口: 对方法传入的参数,以及返回值进行约束 (可批量约束)

interface encrypt {
  (key: string, val: string):string
}

var md5:encrypt = function(key: string, val: string):string {
  return `${key} + ${val}`
}

console.log(md5('test', '123'))

可索引接口,对数组/对象的约束

// 可索引接口 对数组的约束
interface UserArr {
  [index: number]: string
}

var arrTest: UserArr = ['123', '112']

console.log(arrTest[0])

// 可索引接口 对对象的约束
interface UserObj {
  [index: string]: string
}

var usrObj:UserObj = {
  name: '20'
}

console.log(usrObj.name)

类类型接口

// 类类型接口:对类的约束 和抽象类有点类似
interface Animal {
  name: string;
  eat(str: String):void;
}

class Dog implements Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  // 必须有eat方法,eat方法可不传参数
  eat() {
    console.log(this.name + '吃粮食')
  }
}

var d = new Dog('xxiaohei')
d.eat()

class Cat implements Animal {
  name: string;
  constructor(name: string) {
    this.name = name
  }
  eat(food: string) {
    console.log(`${this.name} + ${food}`)
  }
}

var c = new Cat('miaomiao')
c.eat('laoshu')

接口的扩展、接口的继承(接口可以继承接口)

// 例子一
interface Animal {
  eat():void
}

interface Person extends Animal {
  work():void
}

class Web implements Person {
  public name: string;
  constructor(name:string) {
    this.name = name
  }
  eat() {
    console.log(`${this.name} --- chi`)
  }
  work() {
    console.log(`${this.name} --- work`)
  }
}

var ww = new Web('webbbb')
ww.eat()
ww.work()

// 例子二 继承 + 实现(接口扩展)
interface Animal {
  eat():void
}

interface Person extends Animal {
  work():void
}

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

}

class Web extends Programmer implements Person {
  constructor(name:string) {
    super(name)
  }
  eat() {
    console.log(`${this.name} --- chi`)
  }
  work() {
    console.log(`${this.name} --- work`)
  }
}

var ww = new Web('webbbb')
ww.eat()
ww.work()
ww.coding('ts')

泛型

  • 解决类 ,接口,方法的复用性, 以及对不特定数据类型的支持
  • 泛型可以支持不特定的类型数据,要求:传入的参数和返回的参数一致

泛型的定义,泛型函数

// T表示泛型 具体什么类型是调用这个方法的时候决定的
function getData<T>(value:T):T {
    return value
}
// function getData<T>(value:T):any {
//   return 'test'
// }

// getData<Number>('test');  错误写法
getData<Number>(123); // 参数必须是number

泛型类

// 最小堆算法,需要同时支持返回数字和字符串两种类型,通过类的泛型来实现
class MinClass<T> {
  public list: T[] = []
  add(num:T) {
    this.list.push(num)
  }
  min():T {
    var minNum = this.list[0]
    for (let i = 0; i < this.list.length; i++) {
      if (this.list[i] < minNum) {
        minNum = this.list[i]
      }
    }
    return minNum
  }
}

var m = new MinClass<number>() // 实例化类,且制定T代表number

m.add(2)
m.add(3)
m.add(4)

alert(m.min())

var m2 = new MinClass<string>()
m2.add('44')
m2.add('a')
m2.add('v')
alert(m2.min())

泛型接口

// 1. 第一种定义泛型接口的方法
interface ConfigFn {
  <T>(val:T):T
}

var getData:ConfigFn = function<T>(value: T) {
  return value
}

getData<string>('123')

// 2.第二种定义泛型接口的方法
interface ConfigFn<T> {
  (val:T):T;
}

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

var myGetData:ConfigFn<string> = getData;

myGetData('20')

把类作为参数类型的泛型类

  1. 先定义个类
  2. 把类作为参数来约束数据传入的类型

功能一

class User {
  username: string | undefined;
  password: string | undefined;
}

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

var u = new User()
u.username = 'zhangsan'
u.password = '123456'

var 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
  }
}

var a = new ArticleCate()
a.title = '国内'
a.desc = '国内新闻'
a.status = 1

var DB = new MysqlDb()
DB.add(a)

但mySqlDb重复封装了,通过泛型解决

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

// 1.定义一个user类和数据库进行映射
class User {
  username: string | undefined;
  password: string | undefined;
}

var u = new User()
u.username = 'zhangsan'
u.password = '123456'

var DB = new MysqlDb<User>()

DB.add(u)

// 1.定义一个ArticleCate类和数据库进行映射
class ArticleCate {
  title: string | undefined;
  desc: string | undefined;
  status: number | undefined;
  constructor(params: {
    title?: string,
    desc?: string,
    status?: number ,
  }) {
    this.title = params.title
    this.desc = params.desc
    this.status = params.status
  }
}

var a = new ArticleCate({
  title: '分类',
  desc: '111'
})

var DB2 = new MysqlDb<ArticleCate>()

DB2.add(a)
DB2.update(a, 2)

ts类型,接口,类,泛型综合使用

interface DBI<T> {
  add(info: T):boolean;
  update(info: T, id: number):boolean;
  delete():boolean;
  get(id: number): any[]
}

// 定义一个操作mySql数据库的类 注意:要实现泛型接口,这个类也应该是一个泛型类
class MysqlDb<T> implements DBI<T> {
  add(info: T): boolean {
    console.log(info)
    return true
  }
  update(info: T, id: number): boolean {
    throw new Error("Method not implemented.");
  }
  delete(): boolean {
    throw new Error("Method not implemented.");
  }
  get(id: number): any[] {
    var list = [
      {
        title: 'xxxx',
        desc: 'xxx1'
      },
      {
        title: 'xxxx',
        desc: 'xxx1'
      },
    ]
    return list
  }
}

// 定义一个操作mySql数据库的类 注意:要实现泛型接口,这个类也应该是一个泛型类
class MssqlDb<T> implements DBI<T> {
  add(info: T): boolean {
    console.log(info)
    return true
  }
  update(info: T, id: number): boolean {
    throw new Error("Method not implemented.");
  }
  delete(): boolean {
    throw new Error("Method not implemented.");
  }
  get(id: number): any[] {
    var list = [
      {
        title: 'xxxx',
        desc: 'xxx1'
      },
      {
        title: 'xxxx',
        desc: 'xxx1'
      },
    ]
    return list
  }
}

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

var u = new User()
u.username = 'zhangsan'
u.password = '123456'

var oMySql = new MysqlDb<User>(); // 用类约束传入参数的合法性
oMySql.add(u)
console.log(oMySql.get(4))


var oMsSql = new MssqlDb<User>()
oMsSql.add(u)
console.log(oMsSql.get(1))

ts 模块化封装

??榈亩ㄒ?,引用

// db.ts
var dbUrl = 'xxx'

function getData():any[] {
  console.log('获取数据库数据')
  var list = [
    {
      title: '222'
    }, {
      title: '333'
    }
  ]
  return list
}

function saveData() {
  console.log('保存')
}

export {
  dbUrl,
  getData,
  saveData
}

// export default getData // export default在一个??橹兄荒苡靡淮?,引入时import getData from ’xxxx/xxx‘

// index.ts

import { getData as get, saveData } from './modules/db'

get()
saveData()

应用举例:封装db库

// modules/db.ts

interface DBI<T> {
 add(info: T):boolean;
 update(info: T, id: number):boolean;
 delete():boolean;
 get(id: number): any[]
}

export class MssqlDb<T> implements DBI<T> {
 add(info: T): boolean {
   console.log(info)
   return true
 }
 update(info: T, id: number): boolean {
   throw new Error("Method not implemented.");
 }
 delete(): boolean {
   throw new Error("Method not implemented.");
 }
 get(id: number): any[] {
   var list = [
     {
       title: 'xxxx',
       desc: 'xxx1'
     },
     {
       title: 'xxxx',
       desc: 'xxx1'
     },
   ]
   return list
 }
}

// model/user.ts

import { MssqlDb } from '../modules/db'

class UserClass {
 username: string | undefined;
 password: string | undefined;
}

var UserModel = new MssqlDb<UserClass>(); // 用类约束传入参数的合法性

export {
 UserClass,
 UserModel
}

// index.ts

import { UserClass, UserModel } from './model/user'
import  {ArticleClass, ArticleModel } from './model/article'

var user = new UserClass();
user.username = 'zhangsan'
user.password = '123344'

UserModel.add(user)
var res = UserModel.get(123)
console.log(res)

命名空间 命名空间块化

namespace A {
  // ...
}

namespace B {
  // ...
  export class Dog {
    name: string;
    constructor(name:string) {
      this.name = name
    }
  }
}

// 调用命名空间中的方法,或类,需要在namespace中暴露export出来
var d = new B.Dog('jfsldjf')
console.log(d)

可将命名空间当作一个??橹苯颖┞冻隼?/p>

// modules/a.ts
export namespace A {
  // ...
}

// index.ts
import { A } from 'xxxx'
var d = new A.dog('test')

命名空间和??榈那穑好占渲饕糜谧橹耄苊饷逋?;??椴嘀卮氲闹赜?,一个??榭赡芑嵊卸喔雒占?/p>

装饰器

装饰器:是一种特殊类型的声明,能够被附加到类声明,方法,属性,或参数上,可以修改类的行为
通俗的讲,装饰器就是一个方法,可以注入到类,方法,属性参数上来扩展类,属性,方法,参数的功能;

常见装饰器有:类装饰器,属性装饰器,方法装饰器,参数装饰器

装饰器的写法:普通装饰器(无法传参);装饰器工厂(可传参)

类装饰器

普通装饰器(无法传参)

// 类装饰器,在类声明之前被声明(紧接着类声明),应用于类构造函数,可用来监视、修改、或替换类定义

// 装饰器
function logClass(params:any) {
  console.log(params) // params 就是当前类
  params.prototype.apiUrl = 'xxxx'
  params.prototype.run = function() {
    console.log('run method')
  }
}

@logClass
class HttpClient {
  constructor() {

  }
  getData() {

  }
}

var http: any = new HttpClient()
console.log(http.apiUrl)
http.run()

装饰器工厂(可传参数)

// 装饰器工厂
function logClass(params: string) {
  return function(target: any) { // target为类
    // console.log(target, params)
    target.prototype.apiUrl = params
  }
}

@logClass('http://hello')
class HttpClient {
  constructor() {

  }
  getData() {

  }
}

var http:any = new HttpClient()
console.log(http.apiUrl)

类装饰器:下面是一个重载构造函数的例子, (修改当前类的构造函数或方法,可看为固定用法)

function logClass(target:any) {
  console.log(target)
  return class extends target {
    apiUrl: any = '修改后数据'
    getData() {
      console.log(`${this.apiUrl} + 修改后的`)
    }
  }
}

@logClass
class HttpClient {
  public apiUrl: string | undefined;
  constructor() {
    this.apiUrl = '我是构造函数里面的apiUrl'
  }
  getData() {
    console.log(this.apiUrl)
  }
}

var http = new HttpClient()
http.getData()

属性装饰器

// 属性装饰器
// 属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数
// 1. 对静态成员来说是类的构造函数,对实例成员来说是类的原型对象
// 2. 成员的名字
function logProperty(params:any) {
  return function (target:any, attr: any) {
    console.log(target, attr)
    target[attr] = params
  }
}

@logClass('http://hello')
class HttpClient {
  @logProperty('newUrl')
  public url: any | undefined
  constructor() {

  }
  getData() {
    console.log('getData===>', this.url)
  }
}

var http = new HttpClient()
http.getData()

方法装饰器

方法装饰器 会应用到方法的属性描述符上,可以用来监视,修改,或者替换方法定义

方法装饰器会在运行时,传入下列三个参数

1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
2. 成员的名字
3. 成员的属性描述符

方法装饰器一: 修改当前实例的属性和方法

function get(params:any) {
  return function(target:any, methodName: any, desc:any) {
    console.log(target, methodName, desc) // 仍可改变类原型上的方法和属性
    target.apiUrl = 'apiUro'
    target.run = function() {
      console.log('run')
    }
  }
}

class HttpClient {
  public url: any | undefined
  constructor() {

  }
  @get('htttp://dksjflsjkf')
  getData() {
    console.log('getData===>', this.url)
  }
}

var http:any = new HttpClient()
console.log(http.apiUrl)
http.run()

方法装饰器二: 修改当前方法

function get(params:any) {
  return function(target:any, methodName: any, desc:any) {
    console.log(target, methodName, desc.value)

    // 修改装饰器的方法,把装饰器方法里面传入的所有参数改为string类型
    // 1. 保存当前方法
    var oMethod = desc.value;

    desc.value = function(...args: any[]) {
      args = args.map(val => String(val))
      console.log(args)
      // 2. 调用原来的旧方法(看是否需要直接覆盖,可省略)
      oMethod.apply(this, args)
    }
    
  }
}

class HttpClient {
  public url: any | undefined
  constructor() {

  }
  @get('htttp://dksjflsjkf')
  getData(...args:any[]) {
    console.log('我是getData', args)
  }
}

var http:any = new HttpClient()
http.getData(123, 'xdd')

方法参数装饰器

参数装饰器表达式会在运行时当作函数被调用,可用使用参数装饰器为类的原型增加一些元素数据,传入下列3个参数

1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
2. 方法的名字
3. 参数在函数参数列表中的索引
function logParam(params: any) {
  return function(target:any, methodName: any, paramsIndex:any) {
    // console.log(params)
    // console.log(target, methodName, paramsIndex)
    target.apiUrl = params
  }
}

class HttpClient {
  public url: any | undefined
  constructor() {

  }
  getData(@logParam('uuid') uuid:any) {
    // console.log(uuid)
  }
}

var http:any = new HttpClient()
console.log(http.apiUrl)
http.getData(123456)

装饰器的执行顺序

  1. 属性 > 方法 > 方法参数 > 类装饰器
  2. 有多个同样的装饰器,则会先执行后面的
function logClass1(params:string) {
  return function(target:any) {
    console.log('类装饰器1')
  }
}

function logClass2(params:string) {
  return function(target:any) {
    console.log('类装饰器2')
  }
}

function logAttr(params?:string) {
  return function(target:any, attr: any) {
    console.log('属性装饰器')
  }
}

function logMethod(params?:string) {
  return function(target:any, methodName: any, desc: any) {
    console.log('方法装饰器')
  }
}

function logParam1(params?: any) {
  return function(target:any, methodName: any, paramsIndex:any) {
    console.log('方法参数装饰器1')
  }
}

function logParam2(params?: any) {
  return function(target:any, methodName: any, paramsIndex:any) {
    console.log('方法参数装饰器2')
  }
}

@logClass1('http://1')
@logClass2('http://2')
class HttpClient {
  @logAttr()
  public url: any | undefined
  constructor() {

  }
  @logMethod()
  getData() {
    return true
  }

  setData(@logParam1() attr1:any, @logParam2() attr2: any) {
  }
}

var http:any = new HttpClient()


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

推荐阅读更多精彩内容