第八节:React组件的生命周期

其实React组件并不是真正的DOM, 而是会生成JS对象的虚拟DOM, 虚拟DOM会经历创建,更新,删除的过程

这一个完整的过程就构成了组件的生命周期,React提供了钩子函数让我们可以在组件生命周期的不同阶段添加操作


1. 生命周期函数的理解

1.1 组件生命周期函数说明
  1. 组件生命周期函数主要分三类,组件的初始挂载,组件的更新渲染以及组件的卸载
  2. 有一些生命周期函数还在三个阶段都会执行的


1.2 组件的生命周期图
生命周期流程图.png


2. 生命周期函数

2.1 组件初始挂载
2.1.1 组件初始挂载生命周期函数认识

当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下:

  1. constructor: 完成React数据的初始化
  2. conponentWillMount/UNSAFE_componentWillMonut: 页面渲染前调用(未来将废弃)
  3. render : class组件中唯一必须实现的方法,返回React元素渲染页面
  4. componentDidMount 页面初始化渲染完毕以后执行


2.1.2 constructor函数

说明:

  1. 如果不需要初始化state,或者不进行方法的绑定,则不需要实现constructor构造函数
  2. 在组件挂载前调用构造函数,如果继承React.Component,则必须调用super(props)
  3. constructor通常用于处理了state初始化和为事件处理函数绑定this实例
  4. 尽量避免将props外部数据赋值给组件内部state状态

注意: constructor 构造函数只在初始化化的时候执行一次


示例代码如下:

class MyCom extends React.Component{
    
    // 1. constructor 构造函数
    constructor(props){
        super(props)
        console.log("组件初始化数据");
        // 初始化组件状态
        this.state = {
            count: 0
        }
        // 处理事件函数绑定组件实例
        this.handleClick = this.handleClick.bind(this)    
    }

    
    handleClick(){
        this.setState(() => ({
            count: ++ this.state.count
        }))


    }
    
    render(){
        return (
            <div>
                <p>点击次数{ this.state.count }</p>
                <button onClick={ this.handleClick }>点击</button>
            </div>
        )
    }
}


// 将组件渲染到页面上
ReactDOM.render(<MyCom/> ,document.getElementById("root"))


之前有讲过组件state也可以不定义在constructor构造函数中,事件函数也可以通过箭头函数处理this问题

因此如果不想使用constructor 也可以将两者移出

示例代码如下

class MyCom extends React.Component{
  
    // 初始化组件状态
    state = {
        count: 0
    }

    // 箭头函数处理this问题
    handleClick= ()=>{
        this.setState(() => ({
            count: ++ this.state.count
        }))
    }
   //... 
}

结果一样正常显示


2.1.3 componentWillMount函数

说明:

  1. componentWillMount生命周期函数在组件渲染前执行,
  2. 使用时函数能正常运行, 但是控制台会打印警告,推荐使用UNSAFE_componentWillMount
  3. 但是react官网表示UNSAFE_componentWillMount即将过时,不建议使用
  4. 这个生命周期函数也只会执行一次

这个生命周期函数一般使用较少


示例代码:

class MyCom extends React.Component{
    // 1. 初始化构造函数
    constructor(props){
        super(props)
        console.log("组件初始化数据");
        // 初始化组件状态
        this.state = {
            count: 0
        }
        // 处理事件函数绑定组件实例
        this.handleClick = this.handleClick.bind(this)    
    }

    // 2.组件渲染前执行
    UNSAFE_componentWillMount(){
        console.log("组件内容渲染前执行 conponentWillMount");

    }

    handleClick(){
        this.setState(() => ({
            count: ++this.state.count
        }))


    }
    render(){
        return (
            <div>
                <p>点击次数{ this.state.count }</p>
                <button onClick={ this.handleClick }>点击</button>
            </div>
        )
    }
}


// 将组件渲染到页面上
ReactDOM.render(<MyCom/> ,document.getElementById("root"))


2.1.4 render渲染函数

说明:

  1. class组件中唯一必须实现的方法,其他生命周期函数没有需求可以不写,这个必须实现
  2. render函数返回一个通过JSX语法创建的React元素
  3. render函数应为纯函数,意味着在不修改组件状态和父组件传递的props时,每次返回相同的结果
  4. render函数初始只会渲染一次,但是每次状态的改变都会重新执行


示例代码:

class MyCom extends React.Component{
    // 1. 初始化构造函数
    constructor(props){
        super(props)
        console.log("组件初始化数据");
        // 初始化组件状态
        this.state = {
            count: 0
        }
        // 处理事件函数绑定组件实例
        this.handleClick = this.handleClick.bind(this)    
    }

    // 2.组件渲染前执行
    UNSAFE_componentWillMount(){
        console.log("组件内容渲染前执行 conponentWillMount");

    }

    // 3. render渲染函数
    render(){
        console.log("render 渲染函数")
        return (
            <div>
                <p>点击次数{ this.state.count }</p>
                <button onClick={ this.handleClick }>点击</button>
            </div>
        )
    }

    // 自定义事件函数
    handleClick(){
        this.setState(() => ({
            count: ++this.state.count
        }))


    }
}


// 将组件渲染到页面上
ReactDOM.render(<MyCom/> ,document.getElementById("root"))


2.1.5 componentDidMount函数

说明:

  1. 组件渲染完毕以后执行, 在render渲染函数之后
  2. componentDidMount生命周期函数只会执行一次
  3. 可以在这个函数中发送ajax请求


示例代码:

class MyCom extends React.Component{
    // 1. 初始化构造函数
    constructor(props){
        super(props)
        console.log("组件初始化数据");
        // 初始化组件状态
        this.state = {
            count: 0
        }
        // 处理事件函数绑定组件实例
        this.handleClick = this.handleClick.bind(this)    
    }

    // 2.组件渲染前执行
    UNSAFE_componentWillMount(){
        console.log("组件内容渲染前执行 conponentWillMount");

    }

    // 3. render渲染函数
    render(){
        console.log("render 渲染函数")
        return (
            <div>
                <p>点击次数{ this.state.count }</p>
                <button onClick={ this.handleClick }>点击</button>
            </div>
        )
    }

    // 4.组件渲染完毕后执行 
    componentDidMount(){
        console.log("组件内容渲染完毕,componentDidMount");

    }

    // 自定义事件函数
    handleClick(){
        this.setState(() => ({
            count: ++this.state.count
        }))


    }
}


// 将组件渲染到页面上
ReactDOM.render(<MyCom/> ,document.getElementById("root"))


2.2 组件渲染更新

组件的更新会出现两种状况, 父组件传递的props更新以及当前组件更新自己的state

2.2.1 组件渲染更新生命周期函数认识
  1. componentWillReceiveProps 组件接受的Props将要更新
  2. shouldComponentUpdate 是否允许组件渲染更新,函数返回true表示通过, false表示不通过,渲染不更新
  3. componentWillUpdate/UNSAFE_componentWillUpdate 组件内容更新渲染前执行
  4. render 组件内容更新渲染
  5. componentDidUpdate 组件内容更新渲染之后执行


2.2.2 componentWillReceiveProps函数

说明:

  1. 在父组件传递的props更新时执行的生命周期函数
  2. 函数接受一个参数nextProps,为更新后的props数据
  3. 使用时控制台会打印警告, 建议使用UNSAFE_componentWillReceiveProps
  4. 但是官网表示UNSAFE_componentWillReceiveProps也将会被废弃



示例代码如下:

// 子组件
class MyCom extends React.Component{
  
  // 初始化组件状态
  state = {
    count: 0
  }

  // 1. 组件将要接受props更新
  componentWillReceiveProps(){
    console.log("组件将要接受props更新: componentWillReceiveProps");
  }


  render(){
    console.log("render 渲染函数")
    return (
      <div>
        <p>父组件传递props数据{ this.props.num }</p>
        <p>子组件state数据{ this.state.count }</p>
        <button onClick={ this.handleClick }>子组件按钮</button>
      </div>
    )
  }

  // 自定义事件函数
  handleClick=()=>{
      this.setState(() => ({
        count: ++this.state.count
      }))


  }
}


// 父组件
class MyParent extends React.Component{
  state = {
    num:0
  }

  changeNum = () => {
    this.setState(() => ({
      num: ++ this.state.num
    }) )
  }

  render(){
    return (
      <div>
        <button onClick={ this.changeNum }>父组件按钮</button> 
        <MyCom num={this.state.num}/>
      </div>
    )
  }
}


// 将组件渲染到页面上
ReactDOM.render(<MyParent /> ,document.getElementById("root"))


2.2.3 shouldComponentUpdate函数

说明:

  1. shouldComponentUpdate函数使用来判读是否更新渲染组件
  2. 函数返回值是一个布尔值,为true,表示继续走其他的生命周期函数,更新渲染组件
  3. 如果返回一个false表示,不在继续向下执行其他的生命周期函数,到此终止,不更新组件渲染
  4. 函数接受两个参数, 第一个参数为props将要更新的数据, 第二个参数为state将要更新的数据


示例代码如下:

// 子组件
class MyCom extends React.Component{
  
  // 初始化组件状态
  state = {
    count: 0
  }

  // 1. 组件将要接受props更新
  componentWillReceiveProps(nextProps){
    console.log("组件将要接受props更新: componentWillReceiveProps");
   
    
  }

  // 2. 是否允许组件渲染更新
  shouldComponentUpdate(nextProps, nextState){
    console.log("是否允许组件渲染更新: shouldComponentupdate");
    return true
  }

 
  render(){
    console.log("render 渲染函数")
    return (
      <div>
        <p>父组件传递props数据{ this.props.num }</p>
        <p>子组件state数据{ this.state.count }</p>
        <button onClick={ this.handleClick }>子组件按钮</button>
      </div>
    )
  }
  // 自定义事件函数
  handleClick=()=>{
      this.setState(() => ({
        count: ++this.state.count
      }))


  }
}


// 父组件
//...


2.2.4 componentWillUpdate 函数

说明:

  1. componentWillUpdate组件更新渲染前执行
  2. 函数接受两个参数,第一个是props将要更新的数据,第二个是state将要更新的数据
  3. 使用是浏览器会警告, 建议使用UNSAFE_componentWillUpdate
  4. 但是官网表示UNSAFE_componentWillUpdate也将被废弃


示例代码:

class MyCom extends React.Component{
  
  // 初始化组件状态
  state = {
    count: 0
  }

  // 1. 组件将要接受props更新
 componentWillReceiveProps(nextProps){
    console.log("组件将要接受props更新: componentWillReceiveProps");
   
    
  }

  // 2. 是否允许组件渲染更新
  shouldComponentUpdate(nextProps, nextState){
    console.log("是否允许组件渲染更新: shouldComponentupdate");
    return true
  }

  // 3.组件渲染更新前
  componentWillUpdate(nextProps, nextState){
    console.log("组件内容更新前: componentWillUpdate");
   
  }

  render(){
    console.log("render 渲染函数")
    return (
      <div>
        <p>父组件传递props数据{ this.props.num }</p>
        <p>子组件state数据{ this.state.count }</p>
        <button onClick={ this.handleClick }>子组件按钮</button>
      </div>
    )
  }


  // 自定义事件函数
  handleClick=()=>{
      this.setState(() => ({
        count: ++this.state.count
      }))


  }
}


// 父组件
//... 


2.2.5 render函数

更初始化一样,没事数据更新都会触发render函数重新执行, 更新页面渲染


2.2.6 componentDidUpdate函数

说明:

  1. 组件render执行后,页面渲染完毕了以后执行的函数
  2. 接受两个参数,分别为更新前的props和state


示例代码如下:

// 子组件
class MyCom extends React.Component{
  
  // 初始化组件状态
  state = {
    count: 0
  }

  // 1. 组件将要接受props更新
 componentWillReceiveProps(nextProps){
    console.log("组件将要接受props更新: componentWillReceiveProps");
   
    
  }

  // 2. 是否允许组件渲染更新
  shouldComponentUpdate(nextProps, nextState){
    console.log("是否允许组件渲染更新: shouldComponentupdate");
    return true
  }

  // 3.组件渲染更新前
  componentWillUpdate(){
    console.log("组件内容更新前: componentWillUpdate");
   
  }

  // 4. render渲染函数
  render(){
    console.log("render 渲染函数")
    return (
      <div>
        <p>父组件传递props数据{ this.props.num }</p>
        <p>子组件state数据{ this.state.count }</p>
        <button onClick={ this.handleClick }>子组件按钮</button>
      </div>
    )
  }

  // 5. 组件内容更新渲染后
  componentDidUpdate( prevProps, prevState){
    console.log("组件内容更新后执行");
  }


  // 自定义事件函数
  handleClick=()=>{
      this.setState(() => ({
        count: ++this.state.count
      }))


  }
}


// 父组件
//...


2.3 组件销毁

说明:

  1. 组件销毁阶段只有一个生命周期函数componentWillUnmount
  2. componentWillUnmont组件销毁前执行的生命周期函数,
  3. 没有组件销毁后执行的生命周期函数, 没什么意义,组件被销毁了,获取不到对应的内容了
  4. 通过会在组件销毁前清理一些不会被组件自动清理的内容, 如: 定时器,或一些特殊的事件绑定


示例代码:

// 子组件
class MyCom extends React.Component{

    // 初始化组件状态
    state = {
        count: 0
    }

    render(){
        console.log("render 渲染函数")
        return (
            <div>
                <p>父组件传递props数据{ this.props.num }</p>
                <p>子组件state数据{ this.state.count }</p>
                <button onClick={ this.handleClick }>子组件按钮</button>
            </div>
        )
    }

    componentWillUnmount(){
        console.log("组件被销毁前执行:componentWillUnmount")
    }


    // 自定义事件函数
    handleClick=()=>{
        this.setState(() => ({
            count: ++this.state.count
        }))

    }
}


// 父组件
class MyParent extends React.Component{
    state = {
        isShow: true
    }

    changeNum = () => {
        this.setState(() => ({
            isShow: !this.state.isShow
        }) )
    }

    render(){
        return (
            <div>
                <button onClick={ this.changeNum }>父组件按钮</button> 
                { this.state.isShow ? <MyCom num={this.state.num}/>: "组件不显示"}
            </div>
        )
    }
}


// 将组件渲染到页面上
ReactDOM.render(<MyParent /> ,document.getElementById("root"))


2.4 getSnapshotBeforeUpdate函数

说明:

  1. getSnapshotBeforeUpdate必须跟componentDidUpdate一起使用,否则就报错
  2. 但是不能与componentWillReceivePropscomponentWillUpdate一起使用
  3. state和props更新都会触发这个函数的执行, 在render函数之后执行
  4. 接受两个参数,更新前的props和当前的state
  5. 函数必须return 返回结果
  6. getSnapshotBeforeUpdate返回的结果将作为参数传递给componentDidUpdate


示例代码如下:

class MyCom extends React.Component{
  
  // 初始化组件状态
  state = {
    count: 0
  }

  render(){
    console.log("render 渲染函数")
    return (
      <div>
        <p>父组件传递props数据{ this.props.num }</p>
        <p>子组件state数据{ this.state.count }</p>
        <button onClick={ this.handleClick }>子组件按钮</button>
      </div>
    )
  }

  getSnapshotBeforeUpdate(){
    console.log("getSnapshotBeforeUpdate")
    
    return true
  }

  componentDidUpdate(){
    console.log("组件内容更新后执行");
    
  }


  // 自定义事件函数
  handleClick=()=>{
      this.setState(() => ({
        count: ++this.state.count
      }))
  }
}


// 父组件
class MyParent extends React.Component{
  state = {
    isShow: true,
    num : 0
  }

  changeShow = () => {
    this.setState(() => ({
      isShow: !this.state.isShow
    }) )
  }

  changeNum = () => {
    this.setState(() => ({
      num: ++this.state.num
    }) )
  }

  render(){
    return (
      <div>
        <button onClick={ this.changeShow }>父组件按钮</button> 
        <button onClick={ this.changeNum }>更新props</button> 
        { this.state.isShow ? <MyCom num={this.state.num}/>: "组件不显示"}
      </div>
    )
  }
}


// 将组件渲染到页面上
ReactDOM.render(<MyParent /> ,document.getElementById("root"))


2.5 生命周期函数参数
生命周期函数参数.png


2.6 特殊情况的生命周期函数

在React 17 版本之后将会改变几个生命周期函数

更改的生命周期函数.png


3. React 新增生命周期函数

3.1 新版生命周期图

添加静态方法后的生命周期函数图

新的生命周期函数图.png
不常用生命周期图.png


3.2 新增的静态方法

说明:

  1. react新增了静态方法getDerviedStateFromProps方法在生命周期中
  2. 这个方法用来替换componentWillReceiveProps,
  3. 通常会在ComponentWillReceiveProps中利用Props更新state
  4. getDerivedStateFromProps方法接受两个参数, 将要更新的props和state属性
  5. 需要返回一个布尔值,不然会报错
  6. 还可以取代componentWillMount的功能, 因为这个静态方法在组件初始化也会执行


示例代码:

class MyCom extends React.Component{
  
  // 初始化组件状态
  state = {
    count: 0
  }

  // 生命周期上新增的静态方法
  static getDerivedStateFromProps(nextProps,nextState){
    console.log("getDerivedStateFromProps");
      
      // 利用props的值更新当前组件的状态
    nextState.count = nextProps.num
    return true
  }


  render(){
    console.log("render 渲染函数")
    return (
      <div>
        <p>父组件传递props数据{ this.props.num }</p>
        <p>子组件state数据{ this.state.count }</p>
        <button onClick={ this.handleClick }>子组件按钮</button>
      </div>
    )
  }


  // 自定义事件函数
  handleClick=()=>{
      this.setState(() => ({
        count: ++this.state.count
      }))


  }
}


// 父组件
class MyParent extends React.Component{
  state = {
    isShow: true,
    num : 0
  }

  changeShow = () => {
    this.setState(() => ({
      isShow: !this.state.isShow
    }) )
  }

  changeNum = () => {
    this.setState(() => ({
      num: ++this.state.num
    }) )
  }

  render(){
    return (
      <div>
        <button onClick={ this.changeShow }>父组件按钮</button> 
        <button onClick={ this.changeNum }>更新props</button> 
        { this.state.isShow ? <MyCom num={this.state.num}/>: "组件不显示"}
      </div>
    )
  }
}


// 将组件渲染到页面上
ReactDOM.render(<MyParent /> ,document.getElementById("root"))


4. 组件更新的方法

组件更新自己的状态,除了使用setState更新外,还可以通过forceUpdate更新

4.1 forceUpdate

说明:

  1. 在组件中也可以组件实例调用forceUpdate方法直接更新数据
  2. forceUpdate方法会强制更新状态,
  3. forceUpdate方法会执行静态方法getDerivedStateFromProps函数
  4. 但是forceUpdate方法不会触发shouldComponetUpdate判断是否更新的生命周期函数


示例代码:

class MyCom extends React.Component{

    // 初始化组件状态
    state = {
        count: 0
    }

    // 2. 是否允许组件渲染更新
    shouldComponentUpdate(nextProps, nextState){
        console.log("是否允许组件渲染更新: shouldComponentupdate");
        // nextState.count = nextProps.num
        return true
    }

    
    static getDerivedStateFromProps(nextProps,nextState){
        console.log("getDerivedStateFromProps");
        
        console.log(arguments);

        return true
    }


    // 自定义事件函数
    handleClick=()=>{
        this.state.count = ++ this.state.count

        this.forceUpdate();
    }

    // 4. render渲染函数
    render(){
        console.log("render 渲染函数")
        return (
            <div>
                <p>父组件传递props数据{ this.props.num }</p>
                <p>子组件state数据{ this.state.count }</p>
                <button onClick={ this.handleClick }>子组件按钮</button>
            </div>
        )
    }
}


// 父组件
//...

示例说明:

  1. 示例中直接修改状态并不会触发重新渲染
  2. 但是通过组件实例调用forceUpdate强制更新,会重新触发页面渲染
  3. 会触发生命周期getDerivedStateFromProps函数执行,
  4. 但是不会是否判断是否更新的shouldComponentUpdate函数的执行


5. 生命周期总结

5.1 常用生命周期函数

说明:

  1. React生命周期函数很多, 但是并不是每一个都是那么的常用
  2. 因此可以将生命周期图简化一下

常用生命周期图

常用生命周期图.png


5.2 生命周期总结
5.2.1 组件的三个生命周期分三个阶段
  1. Mount : 初始化插入真实DOM
  2. Update : 数据更改重新渲染
  3. Unmount: 被移出真实的DOM


5.2.2 生命周期不同阶段的钩子函数
  • 第一次初始化渲染显示: ReactDOM.render()

    • constructor(): 创建对象初始化state

    • componentWillMount() : 将要插入回调

    • render(): 用于插入虚拟DOM回调

    • componentDidMount() : 已经插入回调(启动定时器,发送ajax,只执行一次)

  • 每次更新 state: this.setState()

    • componentWillUpdate() : 将要更新回调

    • render() : 更新(重新渲染)

    • componentDidUpdate() : 已经更新回调

  • 移除组件 : ReactDOM.unmountComponentAtNode(containerDom)
    • componentWillUnmount() : 组件将要被移出回调(收尾工作,例如清除定时器)


5.2.3 重要的钩子函数
  • render(): 初始化渲染或更新渲染调用

  • componentDidMount() : 开启监听,发送ajax请求

  • componentWillUnmount(): 做一些收尾工作,如,清理定时器


5.3 示例代码:

// 1. 定义组件
class Files extends React.Component {

    constructor (){
        super()

        // 定义状态
        this.state = {
            opacity: 1
        }

    }
    removeComponent () {
        // 执行unmountComponentAtNode()移出DOM节点
        ReactDOM.unmountComponentAtNode(document.getElementById('root'))
    }


    // 组件添加完后执行的钩子函数
    componentDidMount () {
        console.log('componentDidMount()')

        // 开启定时器
        this.timer = setInterval(function(){
            console.log('定时器...')

            // 1. 获取状态中的值
            let {opacity} = this.state;

            // 2. 改变透明度
            opacity -= 0.1;

            // 3. 判断透明度,如果小于0,就变为1
            if(opacity <= 0){
                opacity = 1
            }

            // 4. 改变状态
            this.setState({
                opacity
            })

        }.bind(this),200)
    }


    // 组件被移出后执行的钩子函数
    componentWillUnmount(){
        console.log('componentWillUnmount()')

        // 组件被移除后清除定时器
        clearInterval(this.timer)
    }

   
    render(){
        console.log('render()')
        // 取出状态中的透明度
        let {opacity} = this.state;

        return (
            <div>
                <h2 style={{opacity:opacity}}>{this.props.msg}</h2>
                <button onClick={this.removeComponent}>删除组件</button>
            </div> 
        )
    }
}

// 设置props类型
Files.propTypes = {
    msg: PropTypes.string
}


// 2. 渲染组件标签
ReactDOM.render(
    <Files msg="我太难了" />, 
    document.getElementById('root')
)


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