前端学习笔记三十九-移动APP(3)ReactJS

一、ReactJS简介

  • React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC(Model View Controller) 框架都不满意,就决定自己写一套,用来架设 Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了
  • 由于 React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。所以,越来越多的人开始关注和使用,认为它可能是将来 Web 开发的主流工具。

二、库(library)和框架(FrameWork):

库:小而轻巧,只提供特定Api;优点是船小好调头,可以很方便地从一个库切换到另一个库(如jQuery到Zepto),代码几乎不需要怎么改动。
框架:大而全,提供一整套解决方案。项目从一个框架切换到另一个是比较困难的。

三、三大主流框架

Angluar:最早(出来得最早),在印度用得比较多

  • 出来最早的前端框架,学习曲线比较陡,NG1学起来比较麻烦,NG2开始,进行了一系列的改革,也开始启用组件化了;在NG中,也支持使用TS(TypeScript)进行编程;

Vue:最火(关注的人多),在中国用得比较多。对我我们来说,文档要友好一些。
React:最流行(用的人多)在国外用得比较多,因为它的设计很优秀。

四、React和Vue的对比

组件化方面:
  1. 什么是模块化:是从代码的角度来进行分析的;把编程时候的业务逻辑,分割抽离到不同的模块中来进行开发,这样能够方便代码的重用,便于项目的维护和开发;
  2. 什么是组件化: 是从 UI 界面的角度来进行分析的;把一些可复用的UI元素,抽离为单独的组件;随着我们项目的开发,我们手里的组件会越来越多,到后面我们如果要实现一个页面,可能直接把现有的组件拿过来进行拼接,就能快速得到一个完整的页面, 这样方便了UI元素的重用组件是元素的集合体
  3. 组件化的好处:随着项目规模的增大,手里的组件越来越多;很方便就能把现有的组件,拼接为一个完整的页面;
  4. Vue是如何实现组件化的: 通过 .vue 文件,来创建对应的组件,一个包含以下三个部分;
    • template 结构
    • script 行为
    • style 样式
      导入使用: import Home from './Home.vue'
      浏览器不识别这样的.vue文件,所以在运行前,会把 .vue 预先编译成真正的组件;
  5. React如何实现组件化:React实现组件化的时候,并没有像.vue这样的组件模板文件;而是直接使用JS代码的形式,去创建任何你想要的组件。
  • React全部使用JS来实现一个组件,也就是说:结构、样式、业务逻辑是混合在JS里面一起编写出来的。
  • 要学习React,JS要合格;ES6 和 ES7 (async 和 await) 要会用
移动APP开发体验比较:
  • Vue,结合 Weex 这门技术,提供了迁移到移动端App开发的体验(Weex,目前只是一个小的玩具, 并没有很成功的大案例;都是阿里自己的项目在用)
  • React,结合 ReactNative,也提供了无缝迁移到移动App的开发体验(RN用的最多,也是最火最流行的,大公司用得多);

五、为什么要学习React

  1. 和Angular1相比,React设计很优秀,一切基于JS并且基于组件化开发的思想;
  2. 开发团队实力强悍,不必担心断更的情况;
  3. 社区强大,很多问题都能找到对应的解决方案;
  4. 提供了无缝转到 ReactNative 上的开发体验,让我们技术能力得到了拓展;增强了我们的核心竞争力;
  5. 很多企业中,前端项目的技术选型采用的是React.js

六、React中几个核心的概念

1.虚拟DOM(Virtual Document Object Model)
  • DOM的本质是什么:就是用JS表示的UI元素。浏览器中的概念,用JS对象来表示页面上的UI元素,并提供了操作 DOM 对象的API;
  • 什么是React中的虚拟DOM:是框架中的概念,是程序员用JS对象来模拟页面上的 DOM 和 DOM嵌套;
  • 为什么要实现虚拟DOM(虚拟DOM的目的):为了实现页面中, DOM 元素的高效更新
  • DOM和虚拟DOM的区别
    • DOM:由浏览器中的JS提供功能,所以我们只能人为的使用浏览器提供的固定的API来操作DOM对象;
    • 虚拟DOM:是框架中的概念,不是由浏览器提供的,而是程序员手动模拟实现的,类似于浏览器中的DOM,但是有着本质的区别。
      • 本质: 用JS对象,来模拟DOM元素和嵌套关系;
      • 目的:就是为了实现页面元素的高效更新;


        虚拟DOM的概念
2.Diff算法
  • tree diff:新旧两棵DOM树,逐层对比的过程,就是Tree Diff; 每当我们从前到后,把整颗DOM逐层的节点对比完毕,必然能够找到所有需要被按需更新的元素;
  • component diff:在进行Tree Diff的时候,每一层中,组件级别的对比,叫做 Component Diff;当对比组件的时候,如果两个组件的类型相同,则暂时认为这个组件不需要被更新,如果组件的类型不同,则立即将旧组件移除,新建一个组件,替换到被移除的位置;
  • element diff: 在进行组件对比的时候,如果两个组件类型相同,则需要进行元素级别的对比,如果元素内容不同,则进行相应的替换修改;
  • key:key这个属性,可以把 页面上的 DOM节点 和 虚拟DOM中的对象,做一层关联关系;
    Diff算法图

七、创建基本的webpack4.x项目

  1. 运行npm init -y 快速初始化项目
  2. 在项目根目录创建src源代码目录和dist产品目录(发布的产品所在目录)
  3. 在 src 目录下创建 index.html
  4. 使用 cnpm 安装 webpack ,运行cnpm i webpack -Dcnpm i webpack-cli -D(开发依赖)
    • 如何安装 cnpm: 全局运行 npm i cnpm -g
  5. webpack.config.js配置:webpack 4.x 提供了 约定大于配置的概念;目的是为了尽量减少配置文件的体积;
    • 默认约定了:打包的入口是src -> index.js(新建一个index.js)
    • 打包的输出文件是dist -> main.js
    • 4.x 中 新增了 mode 选项(必选项),可选的值为:developmentproduction; production模式会压缩打包文件的格式。如果另外写了配置,如指定entry:''(入口路径),那么就会覆盖默认的约定
  6. 执行打包webpack,注意,如果执行后报了Cannot find module 'webpack-cli'的提示,说明需要全局安装webpack-cli,命令行运行npm i webpack-cli -g
  7. 打包完毕后dist下自动生成了打包文件main.js,将它手动引入到index.html中<script src="../dist/main.js"></script>
  8. 安装webpack-dev-server,npm i webpack-dev-server -D,快速搭建本地运行环境的工具。执行它的命令即是webpack-dev-server,在package.json里做了如下配置后,可直接执行npm run dev来替代
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server"
  },
  1. 重新配置打包文件路径,webpack-dev-server会帮助我们自动编译
    webpack-dev-server打包好的main.js托管到了内存中,所在在项目根目录中看不到;出于性能上的考虑,不用反复读取物理磁盘
    但是我们可以认为,在项目根目录中,有一个不可见的main.js,然后直接在index.html中引入<script src="/main.js"></script>
    执行入口文件自动编译
webpack-dev-server几个配置项:
  • --open是重新编译后自动打开浏览器 --open firefox(浏览器名称) 则自动用火狐浏览器打开
  • --port 3000 是自定义端口
  • --hot 热更新
  • --host 127.0.0.1 指定域名
  • --progress 显示打包的进度
  • --compress 开启gzip压缩
"dev": "webpack-dev-server --open --port 3000 --hot --host 127.0.0.1 --progress --compress"

配置完执行npm run dev,会用chorme自动打开http://127.0.0.1:3000/(注意:cnpm只能用来安装包,其他操作都需要用npm来执行)

  1. 安装html-webpack-plugin来把页面托管生成到内存中 npm i html-webpack-plugin -D
    在webpack-config.js中配置:
const path = require('path')
const HtmlWebPackPlugin = require('html-webpack-plugin');//导入在内存中自动生成index页面的插件

//创建一个html-webpack-plugin插件的实例对象
const htmlPlugin = new HtmlWebPackPlugin({
    template: path.join(__dirname,'./src/index.html'),//源文件
    filename: 'index.html' //生成在内存中首页的名字
})

module.exports = {
    mode:'development',//development production
    plugins:[
        htmlPlugin
    ]
}

运行后就打开的http://127.0.0.1:3000/就显示index.html的内容了

八、在项目中使用 react

  1. 安装 cnpm i react react-dom -S (生产依赖)
    • react: 专门用于创建组件和虚拟DOM的,组件的生命周期都在这个包中
    • react-dom: 专门进行DOM操作的,最主要的应用场景,就是ReactDOM.render()
  2. index.html页面中,创建容器:
<!--创建一个容器,将来用来渲染的虚拟DOM,将放到这个容器内显示-->
<div id="app"></div>
  1. index.js中,导入包:
import React from 'react'
import ReactDOM from 'react-dom'
  1. 用React提供的JS API创建虚拟DOM元素:
// 这是 创建虚拟DOM元素的 API    <h1 title="啊,五环" id="myh1">你比四环多一环</h1>
//参数1: 创建的元素类型,格式为字符串
//参数2: 是一个对象或null,表示当前这个DOM元素的属性
//参数3: 子节点(包括其他虚拟DOM 或 文本子节点)
//参数n:其他子节点,即多个子节点就一直往后排,用‘,’隔开
const myh1 = React.createElement('h1', { title: '啊,五环', id: 'myh1' }, '你比四环多一环')
  1. 渲染到指定的容器中:
// 使用ReactDOM把虚拟DOM渲染到页面上
//参数1:要渲染的虚拟DOM元素(React.createElement创建出来的)
//参数2:指定渲染到页面上哪个容器,是DOM元素而不是选择器,因此这里不能直接放容器元素的Id字符串,需要放一个容器的DOM对象
ReactDOM.render(myh1, document.getElementById('app'))

九、JSX语法

什么是JSX语法:就是符合 xml 规范的 JS 语法;(语法格式相对来说,要比HTML严谨很多)

  1. 如何启用 jsx 语法?

    • 安装 babel 插件

      • 运行npm i babel-loaderbabel-loader:负责转换
        npm i @babel/core -D
        npm i @babel/plugin-proposal-object-rest-spread -D
        npm i @babel/plugin-transform-runtime -D
        npm i @babel/runtime -S
        注意:这边有个版本对应问题,否则npm run dev后会失败
        现在最新的babel-loader 是8.x版本的,要使用@babel/core,而不是babel-core了。而babel-loader 7.x对应安装babel-core 6.x。
        下面同理:
    • 安装能够识别转换jsx语法的包 npm i @babel/preset-react -D

    • 根目录下添加 .babelrc 配置文件

      {
        "presets": ["@babel/preset-env", "@babel/preset-react", "mobx"],
        "plugins": [
             "@babel/plugin-proposal-object-rest-spread",
             "@babel/plugin-transform-runtime"
         ]
      }
      
    • 添加babel-loader配置项:

      module: { //要打包的第三方模块
          rules: [
            // { test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/ } 效果等价于下面,?表示'x'是0个或者1个
            { test: /\.jsx?$/, use: 'babel-loader', exclude: /node_modules/ }
          ]
      }
      
  2. jsx 语法的本质:并不是直接把用户写的 jsx代码 直接渲染到页面上,而是内部先转换成了 React.createElement 形式,再渲染的;

  3. 在 jsx 中写入 js 表达式:在 jsx 语法中,要把 JS代码写到 { } 中。当编译引擎,在编译jsx代码的时候,如果遇到了<>那么就把它当作 HTML代码去编译,如果遇到了 {} 就把 花括号内部的代码当作普通JS代码去编译;

let a = 10;//渲染数字
let str = '你好,中国';//渲染字符串
let boo = true;//布尔值加入表达式
let title = 'lala';//为属性绑定值
const h1 = <h1>你真可爱</h1>//渲染jsx元素
const arr =[
    <h2>这是h2</h2>,//这是js对象,不是html标签
    <h3>这是h3</h3>
]//渲染jsx元素数组
//将普通字符串数组,转为jsx数组并渲染到页面上【两种方案】
const arrStr =['毛利兰','柯南','灰原哀'];
//方案一
const nameArr= [];
arrStr.forEach(item=>{//forEach没有返回值
    const temp = <h5>{item}</h5>
    nameArr.push(temp);
})
//数组的map方法,对数组的每一项做一个指定的操作,并返回一个新的数组,必须写return
const resultArr = arrStr.map(item=>{
    return item +'~~'
})

//当我们需要在JSX控制的区域内写js表达式,则需要把JS代码写到{}中
ReactDOM.render(<div>
    {a+2}<hr/>
    {str}<hr/>
    {boo?'条件为真':'条件为假'}<hr/>
    <p title={title}></p>
    {h1}
    {arr}
    <hr/>
    {nameArr}
    <hr/>
    {arrStr.map(item=>{
        return <h3>{item}</h3>
    })}
    <hr/>
    {arrStr.map(item => <h3>{item+'1'}</h3>)}
    </div>,document.getElementById('app'))
  1. 在 jsx 中 写注释:推荐使用{ /* 这是注释 */ };因为如果写单行注释//``,}`要换行
  2. 为 jsx 中的元素添加class类名:必须使用className 替代 class,因为 class在ES6中是一个关键字;同样,必须用htmlFor替换label的for属性
  3. 给元素绑定属性的时候用{变量}即可,如<p title={title}></p>
  4. 在JSX创建DOM的时候,所有的节点必须有唯一的根元素进行包裹;
  5. 在 jsx 语法中,标签必须成对出现,如果是单标签,则必须自闭合!

当 编译引擎,在编译JSX代码的时候,如果遇到了<那么就把它当作 HTML代码去编译,如果遇到了 {} 就把 花括号内部的代码当作 普通JS代码去编译;

十、React中第一种创建组件的方式

1. 创建组件
组件的名称首字母必须是大写,不然导入时会识别为html标签

  // 在构造函数中,使用 props 形参,接收外界传递过来的数据
  function Hello(props) {
    //在组件中,必须返回一个合法的JSX虚拟DOM元素
    console.log(props)
     // props.name = 'zs'
    //组件中的props只读,不可以被重新赋值。Vue中也是一样
    return <div>这是 Hello 组件 --- {props.name} --- {props.age} --- {props.gender}</div>
  }

2. 将组件封装到单独的JSX文件中

import React from 'react'
// 在 function定义的组件中,如果想要使用 props,必须先定义形参,否则无法直接使用
// 但是,在class定义的组件中,可以直接使用 this.props 来直接访问,不需要预先接收 props
export default function Hello(props) {
  // console.log(props)
  return <p>haha --- {props.name}</p>
}

3. 在webpack.config.js的module模块中配置:

module: { 
    rules: [
        {
            test: /\.jsx?$/, //表示x字符可有可以没有,即包含jsx和js
            use: "babel-loader",
            exclude: /node_modules/
        }
    ]
}

4. 在导入组件的时候,如何省略组件的.jsx后缀名:

   // 打开 webpack.config.js ,并在导出的配置对象中,新增 如下节点:
   resolve: {
       extensions: ['.js', '.jsx', '.json'], // 表示这几个文件的后缀名可以省略不写。按顺序尝试,如果找不到js后缀的该文件,会去找jsx格式的
       alias: {
           '@': path.join(__dirname, './src') //@就可以表示项目根目录的src这一层目录
       }
     }

5. 在导入组件的时候,配置和使用@路径符号
import Hello from '@/components/Hello'
6. 使用组件
父组件向子组件传递数据
<Hello name={dog.name} age={dog.age} gender={dog.gender}></Hello>
推荐属性扩散的方式,更简便
<Hello {...dog}></Hello>

十一、React中第二种创建组件的方式

使用 class 关键字来创建组件

ES6 中 class 关键字,是实现面向对象编程的新形式;

了解ES6中 class 关键字的使用
  1. class 中 constructor 的基本使用
  2. 实例属性和实例方法
  3. 静态属性和静态方法
  4. 使用 extends 关键字实现继承
用es5演示
//ES5中class关键字,是实现面向对象编程的新形式
function Person(name,age){
    this.name = name
    this.age = age
}
//实例方法
Person.prototype.say = function(){//挂载到构造函数原型对象上的方法,new出来的实例可以继承
    console.log('这是Person的实例方法')
}
//静态方法
Person.show = function(){//实例访问不到,构造函数把它挂载到构造器上了,因此不能通过原型链继承
    console.log('这是Person的静态方法')
}
const p1 =new Person('王多多',18);
console.log(p1);
//通过new出来的实例,访问到的属性,叫做【实例属性】
console.log(p1.name)
p1.say();
Person.show();
//【静态属性】:通过构造函数,直接访问到的属性
Person.info = 'aaa';//info属性直接挂载给了构造函数
console.log(p1.info)//undefined
用es6演示
//创建了一个类
//在class {} 内部,只能写构造器、静态方法、静态属性和实例方法
//class关键字内部,还是用原来的构造函数方法实现的。所以我们把class关键字称做语法糖
class Animal{
    //这是类中的构造器,每一个类中都有一个构造器,如果我们没有手动编写构造器,那么实际上类内部有个看不见的构造器,类似于constructor(){}
    //每当new这个类的时候,会立即执行构造器里的所有代码
    constructor(name,age){
        //实例属性
        this.name = name
        this.age = age
    }
    //在class内部,通过 static 修饰的属性,就是静态属性
    static info = 'eee'//(今后用得不多)
    run(){//挂载到类的原型对象上的方法,可以被实例继承,以后会经常用到
        console.log('这是Animal的实例方法')
    }
    //这是静态方法,只要加了static,都直接挂载到构造器上(今后用得不多)
    static show(){
        console.log('这是Animal的静态方法')
    }
}
const a1 =new Animal('二毛',5);
console.log(a1);
console.log(a1.age)//实例属性
console.log(a1.info)//undefined
console.log(Animal.info) //静态属性
a1.run();
Animal.show();
extends继承演示

父类中的任何属性和方法子类都能继承(包括静态的)

//父类,可以直接把父类理解成原型对象
class Person{
    constructor(name,age){
        this.name = name
        this.age = age
    }
    sayHello(){//实例方法,子类都可以访问到这个方法
        console.log('大家好')
    }
}
//子类,在class类中,可以使用extends关键字,实现子类继承弗雷
//语法: class 子类 extends 父类
class American extends Person{
   constructor(name,age){
       //如果一个子类通过extends关键字继承了父类,那么在子类的构造器中必须先调用super,放在第一行
       //super是一个函数,就是对父类构造器的一个引用
       super(name,age);
   }
}
const a1 =new American('Jack',25);
console.log(a1);
a1.sayHello();
//子类
class Chinese extends Person{
    constructor(name,age,idNumber){
        super(name,age);
        this.idNumber = idNumber;
    }
}
const c1 = new Chinese("张三",28,'330xxxxxxxxxxx0029')
console.log(c1);
c1.sayHello();
基于class关键字创建组件

最基本的组件结构:

   //如果要使用 class 定义组件,必须让该组件继承自 React.Component
   class 组件名称 extends React.Component {
       //this.props直接接收外界传来的参数
       console.log(this.props) //只读,不能重新赋值

       // 在组件内部,必须有 render 函数,作用是渲染当前组件对应的 虚拟DOM结构
       render(){
           // render 函数中,必须返回合法的 JSX 虚拟DOM结构
           return <div>这是 class 创建的组件{this.props}</div>
       }
   }

十二、两种创建组件方式的对比

  1. 构造函数创建出来的组件:专业的名字叫做“无状态组件”(今后用得较少,但是优点是因为剔除了生命周期函数,运行速度相对高一丢丢。电脑性能都较高,因此这个优势也不是很明显)
  2. class关键字创建出来的组件:专业的名字叫做“有状态组件”(今后用得最多)

用构造函数创建出来的组件(无状态组件),和用class创建出来的组件(有状态组件),这两种不同的组件之间的本质区别就是:有状态组件有state属性和自己的生命周期函数,而无状态组件没有

  1. 组件中的 propsstate/data 之间的区别
    • props 中的数据都是外界传递过来的;
    • state/data 中的数据,都是组件私有的;(通过 Ajax 获取回来的数据,一般都是私有数据);
    • props 中的数据都是只读的;不能重新赋值;
    • state/data 中的数据,都是可读可写的;

十三、一个小案例,巩固有状态组件和无状态组件的使用

通过for循环生成多个组件
  1. 数据:
CommentList = [
    { user: '张三', content: '哈哈,沙发' },
    { user: '张三2', content: '哈哈,板凳' },
    { user: '张三3', content: '哈哈,凉席' },
    { user: '张三4', content: '哈哈,砖头' },
    { user: '张三5', content: '哈哈,楼下山炮' }
]

十四、style样式

JSX语法创建的DOM,如果用 style写样式,不能用字符串赋值,需要用js对象来赋值
外面的{}表示这是js代码,里面的{}表示是个对象
如果属性值的单位是px,可以省略px光写数字

   <h1 style={ {color: 'red', fontWeight: 200, fontSize:16} }></h1>

使用CSS模块化

  1. 可以在webpack.config.js中为css-loader启用模块化:
    modules为true表示为普通的CSS样式表启用模块化
{ 
    test: /\.css$/,
    use: [
        'style-loader',
        {
           loader: 'css-loader',//打包处理CSS样式表的第三方loader
           options:{modules:true}//开启CSS模块化
        }
    ]
} 

以下是早版本webpack的配置
css-loader?modules&localIdentName=[name]_[local]-[hash:8]
在做了这个处理后的css文件中,css 模块化只针对类选择器(.title)和Id选择器生效,不会将标签选择器(<h1>、<p>)模块化(仍然全局生效)

  1. 在需要的组件中,import导入样式表,并接收模块化的 CSS 样式对象:
    import cssObj from '../css/CmtList.css'
    然后在需要的HTML标签上,使用className指定模块化的样式:
    <h1 className={cssObj.title}>评论列表组件</h1>
  2. 使用:global()定义全局样式
    全局类名的值不会被改成随机字符
  • :local()包裹的类名(:local默认可以不写,默认的都是:local形式),是被模块化的类名,只能通过className={cssObj.类名}来使用
/*被:global()包裹起来的类名,不会被模块化,而是全局生效*/
:global(.test) {
    font-style: italic
}
.title { //普通写法的则
    color: red
}

十五、安装 React Developer Tools 调试工具

React Developer Tools - Chrome 扩展下载安装地址

总结

理解React中虚拟DOM的概念
理解React中三种Diff算法的概念
使用JS中createElement的方式创建虚拟DOM
使用ReactDOM.render方法
使用JSX语法并理解其本质
掌握创建组件的两种方式
理解有状态组件和无状态组件的本质区别
理解props和state的区别

相关文章

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

推荐阅读更多精彩内容