二、react面向组件编程(一)

摘要: 以前我们熟悉的jquery编程的方式是以面向对象的方式来进行编程的,而react将这种编程方式提升了一个层级,及面向对象---》 面向模块 ----》 面向组件。react面向组件编程无非两个步骤,定义组件和渲染组件。接下来将学习如何定义组件,以及渲染组件。

1. react组件的分类

  • 函数式组件
  • es6类组件
    这两种组件接下来会一一了解到。

2. 自定义组件

2.1) 工厂函数组件(简单组件)如

// 函数式组件必须要有个return
function MyComponent () {
 return <h2>函数式组件</h2>
}

以下用用函数式组件编写最简单的demo

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>react-demo1</title>
  </head>
  <body>
    <div id="root">

    </div>

    <!--react的核心库-->
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <!--是基于react的专门操作dom的扩展库-->
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

    <!-- Don't use this in production: -->
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

    <script type="text/babel">
      // 定义组件
      function MyComponent () {
        return <h2>react 学习</h2>
      }

      // 渲染组件
      ReactDOM.render(<MyComponent/>, document.getElementById('root'))
    </script>

  </body>
</html>

2.2) es6类组件(复杂组件)如

  // 这种方式继承了React的核心组件,并重写了render方法,类实例通过调用render方法来创建虚拟dom
    class MyComponent extends React.Component{
        render () {
          return <h2>学习react类组件</h2>
        }
      }

以下是基于类组件最简单的demo:

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>react-demo1</title>
  </head>
  <body>
    <div id="root">

    </div>

    <!--react的核心库-->
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <!--是基于react的专门操作dom的扩展库-->
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

    <!-- Don't use this in production: -->
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

    <script type="text/babel">
      // 定义组件
      class MyComponent extends React.Component {
        render () {
          return <h2>react 类组件的学习</h2>
        }
      }
      // 渲染组件
      ReactDOM.render(<MyComponent/>, document.getElementById('root'))
    </script>

  </body>
</html>

这里分析类了组件如何定义使用,到这里心中应该有个疑问,既然是类,那么他的人实例应该长什么样子?类组件重写了React的render方法,这个render方法一定是由组件类的实例所调用的,因此在render的方法中是可以访问到这个实例的,其实就i是常见的this,所以有必要在render中打印this一探究竟,如下:

 <script type="text/babel">
      // 定义组件
      class MyComponent extends React.Component {
        render () {
          console.log(this) // 查看组件实例对象
          return <h2>react 类组件的学习</h2>
        }
      }
      // 渲染组件
      ReactDOM.render(<MyComponent/>, document.getElementById('root'))
    </script>

通过打印this得到如下的结果:


image.png

可以看到有属性,有方法。接下来我们就来看看这些属性和方法的作用,(
红色框起来的是重点),究竟是用来干嘛的。

3. 组件三大属性

  • state(react的思想是尽量少操作dom或者不操作dom,而是通过操作数据来改变视图,要操作的数据其实就是state,这个state其实就是组件对象最重要的属性,值是对象,可以包含多个数据,react组件也因此可以叫做状态机,通过更新组件的state来更新对应的页面显示)那么问题就来了,如何初始化这些状态?如何读取某个状态,如何更新某一个状态?这些问题通过以下编码demo的方式来阐述,。
/**
* 首先要先知道以下几点:
* 1. 在构造器中进行初始化操作,react 类组件提供了构造器
* 2. 要更新状态要通过事件触发,那么如何绑定事件
* 3. 通过setState来更新状态的值,更新状态前可能需要读取状态
*
*****/
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>react-demo1</title>
  </head>
  <body>
    <div id="root">

    </div>
    <div id="box">

    </div>
    <!--react的核心库-->
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <!--是基于react的专门操作dom的扩展库-->
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

    <!-- Don't use this in production: -->
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

    <script type="text/babel">
  /**
      * 需求: 自定义组件,功能说明如下:
      *
      * 1. 显示h2标题,初始化为本为: 我对代码如初恋
      * 2. 点击标题更新为: 代码虐我千百遍
      */
    // 定义组件
    class MyLove extends React.Component {

      constructor (props) {
        super(props) // 这是固定写法,react库的常规套路

        // 初始化state
        this.state = {
          isChange: false
        }

        // 绑定this
        this.handleClick = this.handleClick.bind(this)
      }

      // 事件处理函数,函数内部的this并不是组件内部的this,要让this指向组件对象,可以在构造函数中绑定this
      // 通过 this.handleClick = this.handleClick.bind(this)的方式来实现
      handleClick () {
        // 更新状态,注意react中更新状态的唯一方式是通过setState方法,接受一个对象

        // 跟新状态前先获取一下(这里获取后直接取反了)
        const isChange = !this.state.isChange
        // 设置状态
        this.setState({isChange}) // 这是es6的简写, 相当于 this.setState({isChange: isChange})
      }
      render () {

        // 获取状态
        const {isChange} = this.state
        // 注意: onClick事件,很像原声的onclick,但是用了驼峰的写法,因为他并不是原生事件,而且后面不是引号括起来的字符串
        // 而是用{} 括起来的js代码,点击的时候执行函数,在函数里面进行状态的更新,而且onClick={this.handleClick}中的handleClick后面没有加括号,因为react是声明式的,我们只需要告诉他我们要做什么,具体怎么做我们不管,加括号了就相当于我们手动调用了
        return <h2 onClick={this.handleClick}>{isChange ? '代码虐我千百遍' : '我对代码如初恋'}</h2>
      }

    }

    // 渲染虚拟dom到真实dom中
    ReactDOM.render(<MyLove/>, document.getElementById('root'))
    </script>

  </body>
</html>

这个示例尽管简单,但是说明了几个问题,1.修改状态数据确实能改变视图,体现了react的数据驱动思想,2.设置更新状态唯一的方式是通过setState方法,3.通过this.state.属性可以直接获取状态。4.如何进行事件绑定以及this指向的问题的。

  • props属性(state是组件内部的状态,这似乎在有些情况下只有state是不能满足需求的,比如说,自定义一个显示年龄信息的组件,要求显示姓名,性别,年龄,很明显这些要显示的信息不是组件内部特有的属性,而应该是传递给组件的属性,传递给组件的属性其实就是props,很显然这个组件是没有state的,那么可以通过工厂函数组件的方式来创建,函数组件是没有state的,函数组件比类组件效率高,因为函数可以直接调用,而类必须先创建对象,才能调用render函数),接下来就来编写这个年龄信息组件。
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>react-demo1</title>
  </head>
  <body>
    <div id="root">

    </div>
    <div id="box">

    </div>
    <!--react的核心库-->
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <!--是基于react的专门操作dom的扩展库-->
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

    <!-- Don't use this in production: -->
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
  
    <script type="text/babel">
    /***
    * 需求,自定义一个显示年龄信息的组件
    * 要求显示姓名,年龄,性别
    * 从这个需求可以分析出,当前组件应该是没有状态的,他的数据应该都来自外部,因此创建组件可以通过类组件, 也可以通过函数组件
    ************/

    function Person (props) {
      return (
        <ul>
          <li>姓名:{props.name}</li>
          <li>年龄:{props.age}</li>
          <li>性别:{props.sex}</li>
        </ul>
      )
    }

    // 定义人员信息数据
    const person1 = {
      name: '张三',
      age: 20,
      sex: '男'
    }

    // 类似dom标签属性一样给Person组件传值
    ReactDOM.render(<Person name={person1.name} age={person1.age} sex={person1.sex}/>, document.getElementById('root'))
    </script>

  </body>
</html>


这个demo很明显的说明了props的作用,传递给组件Person的属性全部由props接收。但是上面的这个例子还有一些小缺陷,比如,如果age,sex没有传递给组件,呢么Person组件是拿不到age,和sex的。name能不能再age和sex没有被传递的情况下给一个默认值了?如果组件要求name必须传递,age需要传递数值类型的,该如何验证了?首先说明一下,组件是可以给默认值得,也可以做类型和唯一校验的,接下来就添加这些规则:

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>react-demo1</title>
  </head>
  <body>
    <div id="root">

    </div>
    <div id="box">

    </div>
    <!--react的核心库-->
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <!--是基于react的专门操作dom的扩展库-->
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

    <!-- Don't use this in production: -->
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
    <script src="https://unpkg.com/prop-types@15.6/prop-types.js"></script>
    <script type="text/babel">
    /***
    * 需求,自定义一个显示年龄信息的组件
    * 姓名必须指定,如果性别没有指定默认为男
    * 如果年龄没有指定默认为18
    * 从这个需求可以分析出,当前组件应该是没有状态的,他的数据应该都来自外部,因此创建组件可以通过类组件, 也可以通过函数组件,当然也可通过类组件
    ************/
    // 定义组件
    function Person (props) {
      return (
        <ul>
          <li>姓名:{props.name}</li>
          <li>年龄:{props.age}</li>
          <li>性别:{props.sex}</li>
        </ul>
      )
    }

    // 添加默认值规则,通过给函数组件添加一个defaultProps属性来添加默认值
    Person.defaultProps = {
      age: 18,
      sex: '男'
    }

    // 添加类型校验和唯一性校验,通过一个库prop-types来校验,该库是react提供的,通过脚本的方式在上面引入
    // 现在用这种方式来指定
    Person.propTypes = {
      name: PropTypes.string.isRequired,
      age: PropTypes.number
    }

    // 定义人员信息数据
    const person1 = {
      name: '张三',
      age: 20,
      sex: '男'
    }

    const person2 = {
      name: '里斯',
      age: "20"
    }

    // 测试默认值,这里不传递sex和age
    // ReactDOM.render(<Person name={person1.name}/>, document.getElementById('root'))

    // 测试name属性唯一性和age的类型,
    // ReactDOM.render(<Person/>, document.getElementById('root'))//Warning: Failed prop type: The prop `name` is marked as required in `Person`, but its value is `undefined`.in Person

    ReactDOM.render(<Person name={person2.name} age={person2.age} sex="女"/>, document.getElementById('root')) // react.development.js:2721 Warning: Failed prop type: Invalid prop `age` of type `string` supplied to `Person`, expected `number`.


    </script>

  </body>
</html>

该demo虽然简单,但是从从如何传递props,如何做规则校验,如何给默认值都做了说明,可谓麻雀虽小。

  • refs(react尽量不要操作dom,但是有时候不得不操作dom,那么,refs就是用来获取dom元素的,对于设置了ref属性的虚拟dom,可以通过refs属性来获取到dom)这里用一个小demo来阐述一下:
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>react-demo1</title>
  </head>
  <body>
    <div id="root">

    </div>
    <div id="box">

    </div>
    <!--react的核心库-->
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <!--是基于react的专门操作dom的扩展库-->
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

    <!-- Don't use this in production: -->
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
    <script src="https://unpkg.com/prop-types@15.6/prop-types.js"></script>
    <script type="text/babel">
    /***
    * 自定义组件,功能说明下:
    * 1. 点击按钮,提示第一个输入框中的值
    *
    * 2.当第二个输入框失去焦点的时候,提示这个输入框中的值
    *
    *
    *******/

    // 1. 定义组件
    class MyComponent extends React.Component{
      constructor (props) {
        super(props)

        this.showInput = this.showInput.bind(this)
        this.handleBlur = this.handleBlur.bind(this)
      }

      // 这个是通过refs来获取dom元素的
      showInput () {
        const input = this.refs.content // 得到dom元素, 可以通过refs获取到dom对象,进而操作dom

        // alert(input.value)

        // 因为通过ref回调的方式保存了input,所以可以直接获取
        alert(this.input.value)
      }
      // 所有的事件函数都可以接受一个event,这个是通过当前事件回调event来获取的
      handleBlur (event) {
        alert(event.target.value)
      }
      render () {

        /**
        //ref是个字符串
        <input type="text" ref="content"/> &nbsp;&nbsp;
        // ref可以是个回调函数,回调函数的参数就是当前dom元素,这里获取到dom元素input ,将其保存到组件自定义属性input中
        <input type="text" ref={input => this.input = input}/> &nbsp;&nbsp;

        ****/
        return (
          <div>

            <input type="text" ref="content"/> &nbsp;&nbsp;

            <input type="text" ref={input => this.input = input}/> &nbsp;&nbsp;

            <button onClick={this.showInput} >提示输入</button>&nbsp;&nbsp;
            <input type="text" placeholder="失去焦点提示内容" onBlur={this.handleBlur}/>
          </div>
        )
      }
    }

    // 2. 渲染组件标签
    ReactDOM.render(<MyComponent/>, document.getElementById('root'))
    </script>

  </body>
</html>

这个小demo解释了refs属性的用法,通过ref标记dom元素,通过refs来获取dom元素,当然ref可以是字符串,也可以是回调函数,上面例子中的<input type="text" ref={input => this.input = input}/>   就是采用回调的方式,而且这种写法优雅,因为获取dom一次就被存起来了,不用每次都获取。

4. 组件组合使用(组件化)

组件化编程无非以下几个步骤:

  1. 拆分组件: 拆分界面,抽取组件
  2. 实现静态组件: 使用组件实现静态页面效果
  3. 实现动态组件: 动态显示初始化数据,交互功能(从绑定事件监听开始)

比如:实现如下图所示的todoList 案例demo:
image.png

根据以上三个步骤进行编码工作 ,第一步其实就是图示的拆分方式,第二步编写三个静态组件,第三步做交互,改为动态组件。

// 编写静态组件
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>react-demo1</title>
  </head>
  <body>
    <div id="app">

    </div>
    <!--react的核心库-->
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <!--是基于react的专门操作dom的扩展库-->
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

    <!-- Don't use this in production: -->
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
    <script src="https://unpkg.com/prop-types@15.6/prop-types.js"></script>
    <script type="text/babel">
    /**
    * 实现一个简单的todolist案例
    *
    **/

    // 1. 定义组件

    class App extends React.Component{
      render () {
        return (
          <div>
            <h1>todo list</h1>
            <Add/>
            <List/>
          </div>
        )
      }
    }

    // List组件
    class List extends React.Component{
      render () {
        return (
          <ul>
            <li>aaa</li>
            <li>bbb</li>
            <li>ccc</li>
            <li>ddd</li>
          </ul>
        )
      }
    }

    // Add组件
    class Add extends React.Component{
      render () {
        return (
          <div>
            <input type="text"/>
            <button>add</button>
          </div>
        )
      }
    }


    // 渲染组件
    ReactDOM.render(<App/>, document.getElementById('app'))
    </script>

  </body>
</html>



至此,静态组件已经编写完成了,接下来就是改成动态组件,首先需要明确几个问题,这里有三个组件APP,Add,List。那么我们应该吧数据状态放在那个组件中?到这里我们必须明确知道到底需要哪些数据,其实这里只要一个list列表数据就可以了,我们可以称其为todos,这些数据是哪些组件使用的?很明显Add组件用,因为他要往里面添加数据,List也需要,因为他要读取。因此最好的方式是放在App中,因为App是他们共同的父组件,而且todos需要被Add和List共享。由此可以总结为:看数据是某一个组件需要还是某些组件需要,如果是某一个组件需要则放在组件内部,如果是某些组件需要,则放在他们公共的父组件中。

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>react-demo1</title>
  </head>
  <body>
    <div id="app">

    </div>
    <!--react的核心库-->
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <!--是基于react的专门操作dom的扩展库-->
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

    <!-- Don't use this in production: -->
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
    <script src="https://unpkg.com/prop-types@15.6/prop-types.js"></script>
    <script type="text/babel">
    /**
    * 实现一个简单的todolist案例
    *
    **/

    // 1. 定义组件

    class App extends React.Component{

      constructor (props) {
        super(props)

        // 初始化组件状态
        this.state = {
          todos: ['吃饭', '睡觉', '打代码']
        }

        this.addTodos = this.addTodos.bind(this)
      }

      // 更新todos的行为方法,但是有个问题,调用addTodos是在子组件Add中调用的,那么只能通过将addTodos传到子组件执行
      addTodos (todo) {
        // this.state.todos.unshift(todo) 不能这么更改,因为我们知道更改state的唯一方式是setState,只有调用setState才能更新状态

        const {todos} = this.state
        todos.unshift(todo)

        // 更新状态
        this.setState({todos})
      }
      render () {

        const {todos} = this.state
        return (
          <div>
            <h1>todo list</h1>
            <Add count={todos.length} addTodos={this.addTodos}/>
            <List todos={todos}/>
          </div>
        )
      }
    }

    // List组件
    class List extends React.Component{
      render () {
        return (
          <ul>
            {
              // this.props.todos 是一个数据数组,这里需要转为标签数组
              this.props.todos.map((todo, index) => <li key={index}>{todo}</li>)
            }
          </ul>
        )
      }
    }

    // Add组件
    class Add extends React.Component{


      constructor (props) {
        super(props)

        this.add = this.add.bind(this)

      }
      add () {
        // 需要在add 组件修改App组件的状态,即子组件中改变父组件的状态,这是相当困难的,子组件不能直接更改父组件状态,那么怎么改了?
        // 也就是说状态在哪个组件,更新状态的行为就在哪个组件,这里因为todos在App组件中,那么修改todos的方法也在App中,那么在Add中怎么修改了,

        // 1. 读取输入数据
        const todo = this.todoInput.value.trim()
        // 2. 检查合法性
        if (!todo) {
          return
        }
        // 3. 添加
        this.props.addTodos(todo)

        // 清除输入
        this.todoInput.value = '' // this.todoInput其实就是dom的引用
      }
      render () {
        return (
          <div>
            <input type="text" ref={input => this.todoInput = input}/>
            <button onClick={this.add}>add#{this.props.count + 1}</button>
          </div>
        )
      }
    }

    // List组件需要接受一个todos数据,通过这样的方式接受
    List.propTypes = {
      todos: PropTypes.array.isRequired // 表示必须传递一个数组
    }

    Add.propTypes = {
      count: PropTypes.number.isRequired,
      addTodos: PropTypes.func.isRequired
    }
    // 渲染组件
    ReactDOM.render(<App/>, document.getElementById('app'))
    </script>

  </body>
</html>

此demo初步体现了组件化编程的思想。

5. 收集表单数据

表单在开发中都会用到,在react中,将表单组件分为受控和非受控两种,受控组件就是指表单项输入数据能够自动收集成状态,非受控组件是指需要表单项的值时手动读取表单输入框中的数据,以下通过demo来具体说明以下:

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>react-demo1</title>
  </head>
  <body>
    <div id="app">

    </div>
    <!--react的核心库-->
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <!--是基于react的专门操作dom的扩展库-->
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

    <!-- Don't use this in production: -->
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
    <script src="https://unpkg.com/prop-types@15.6/prop-types.js"></script>
    <script type="text/babel">
    /*
    * 受控组件: 自己能够收集表单数据,我们只需要读取状态即可,需要定义状态,需要添加onChange事件,写起来比较麻烦
    * 非受控组件: 我们通过手动收集表单输入框中的值
    */
    class LoginForm extends React.Component{

      constructor (props) {
        super(props)

        // 初始化状态
        this.state = {
          pwd: ''
        }
        this.handleSubmit = this.handleSubmit.bind(this)
        this.handleChange = this.handleChange.bind(this)
      }

      handleSubmit (event) {
        const username = this.nameInput.value

        const pwd = this.state.pwd
        console('用户名为:'+username + '密码为:' + pwd)
        event.preventDefault()

      }

      handleChange (event) {
        // 读取输入的值
        const pwd = event.target.value
        // 更新pwd的状态
        this.setState({pwd})
      }
      render () {
        // 该组件中表单项input既有受控的,也有非受控的,因此当前这个组件既是受控组件也是非受控组件
        return (
          <form onSubmit={this.handleSubmit}>
            用户名: <input type="text" ref={input => this.nameInput = input} />
            密码: <input type="password" value={this.state.pwd} onChange={this.handleChange}/>
            <input type="submit" value="登录"/>
          </form>
        )
      }
    }

    // 渲染dom
    ReactDOM.render(<LoginForm/>,document.getElementById('app'))
    </script>

  </body>
</html>

/**
* 这段代码中,受控项是密码输入框,在输入的时候,会自动收集输入框的值到state* 中,非受控项是用户名输入框,当需要输入框中的值的时候必须手动获取,如 const username = this.nameInput.value 就是在用到的时候才获取的
*
*
**/

以上就是对受控组件和非受控组件的阐述,从代码的简洁性上非受控组件简单,因为非受控组件不需要绑定onChange事件之类的。但是从react的思想出发,受控组件优于非受控组件,因为非受控组件其实就是在操作dom.

6.组件声明周期(组件从生到死的过程)

生命周期流程:
  (一).第一次初始化渲染

  • constructor(): 创建对象初始化state
  • componentWillMount(): 将要插入虚拟dom的回调
  • render(): 用于插入虚拟dom回调
  • componentDidMount(): 已经插入虚拟dom的回调
      (二).每次更新state: this.setState()
    *componentWillUpdate(): 将要更新回调
    *render(): 更新(重新渲染)
    *componentDidUpdate(): 已经更新的回调
      (三).移除组件ReactDom.unmountComponentAtNode(containerDom)
  • componentWillUnmount(): 组件将要被移除的回调

重要的几个钩子函数:

  • render(): 初始化渲染或者更新渲染调用
  • componentDidMount(): 开启监听,发送ajax请求
  • componentWillUnmount(): 组建将要卸载,做一些收尾工作,如清理定时器
  • componentWillReceiveProps(): 接收父组件属性的钩子
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容